diff --git a/backend/src/components/edx/exchange.js b/backend/src/components/edx/exchange.js index 96578dcd2..c126d4f49 100644 --- a/backend/src/components/edx/exchange.js +++ b/backend/src/components/edx/exchange.js @@ -88,9 +88,6 @@ async function getExchanges(req, res) { element['contactIdentifierName'] = tempMinTeam.teamName; } } - if (element['createDate']) { - element['createDate'] = LocalDateTime.parse(element['createDate']).format(DateTimeFormatter.ofPattern('uuuu/MM/dd')); - } }); } return res.status(200).json(dataResponse); @@ -190,10 +187,6 @@ async function getExchange(req, res) { dataResponse['districtName'] = district.name; } - if (dataResponse['createDate']) { - dataResponse['createDate'] = LocalDateTime.parse(dataResponse['createDate']).format(DateTimeFormatter.ofPattern('uuuu/MM/dd')); - } - //creating activities list for timeline display on the frontend dataResponse['activities'] = []; dataResponse['commentsList'].forEach((comment) => { @@ -510,7 +503,8 @@ async function districtUserActivationInvite(req, res) { } const payload = { - ...req.body + ...req.body, + edxUserExpiryDate: req.body.edxUserExpiryDate }; try { const response = await utils.postData(token, config.get('server:edx:districtUserActivationInviteURL'), payload, null, utils.getUser(req).idir_username); @@ -536,7 +530,8 @@ async function schoolUserActivationInvite(req, res) { } const payload = { - ...req.body + ...req.body, + edxUserExpiryDate: req.body.edxUserExpiryDate }; try { const response = await utils.postData(token, config.get('server:edx:schoolUserActivationInviteURL'), payload, null, utils.getUser(req).idir_username); @@ -580,6 +575,7 @@ async function updateEdxUserSchoolRoles(req, res) { selectedUserSchool.updateDate = null; selectedUserSchool.createDate = null; + selectedUserSchool.expiryDate = req.body.params.expiryDate; const result = await utils.putData(token, `${config.get('server:edx:edxUsersURL')}/${selectedUserSchool.edxUserID}/school`, selectedUserSchool, userInfo.idir_username); return res.status(HttpStatus.OK).json(result); @@ -621,6 +617,7 @@ async function updateEdxUserDistrictRoles(req, res) { selectedUserDistrict.updateDate = null; selectedUserDistrict.createDate = null; + selectedUserDistrict.expiryDate = req.body.params.expiryDate; const result = await utils.putData(token, `${config.get('server:edx:edxUsersURL')}/${selectedUserDistrict.edxUserID}/district`, selectedUserDistrict, userInfo.idir_username); return res.status(HttpStatus.OK).json(result); @@ -709,7 +706,7 @@ const createSearchParamObject = (key, value) => { valueType = VALUE_TYPE.UUID; } else if (key === 'createDate') { value.forEach((date, index) => { - value[index] = date + 'T00:00:00'; + value[index] = date; }); if (value.length === 1) { value.push(LocalDateTime.parse(value[0]).plusHours(23).plusMinutes(59).plusSeconds(59)); @@ -856,6 +853,7 @@ async function relinkUserSchoolOrDistrictAccess(req, res) { email: edxUserDetails.email, edxUserId: req.body.params.userToRelink, edxUserSchoolID: req.body.params.userSchoolID, + edxUserExpiryDate: req.body.params.edxUserExpiryDate }; await postData(token, config.get('server:edx:exchangeURL') + '/school-user-activation-relink-saga', payload,null, userName); } else { @@ -870,6 +868,7 @@ async function relinkUserSchoolOrDistrictAccess(req, res) { email: edxUserDetails.email, edxUserId: req.body.params.userToRelink, edxUserDistrictID: req.body.params.edxUserDistrictID, + edxUserExpiryDate: req.body.params.edxUserExpiryDate }; await postData(token, config.get('server:edx:exchangeURL') + '/district-user-activation-relink-saga', payload,null, userName); } diff --git a/backend/src/components/institute/institute.js b/backend/src/components/institute/institute.js index d94eba82d..76c65b3e2 100644 --- a/backend/src/components/institute/institute.js +++ b/backend/src/components/institute/institute.js @@ -58,7 +58,6 @@ async function getDistricts(req, res) { async function addDistrictContact(req, res) { try { const token = getBackendToken(req); - const formatter = DateTimeFormatter.ofPattern('yyyy-MM-dd\'T\'HH:mm:ss'); let district = cacheService.getDistrictJSONByDistrictId(req.body.districtID); if(!district || !hasDistrictAdminRole(req)){ @@ -85,8 +84,8 @@ async function addDistrictContact(req, res) { phoneExtension: req.body.phoneExtension, alternatePhoneNumber: req.body.alternatePhoneNumber, alternatePhoneExtension: req.body.alternatePhoneExtension, - effectiveDate: req.body.effectiveDate ? LocalDate.parse(req.body.effectiveDate).atStartOfDay().format(formatter) : null, - expiryDate: req.body.expiryDate ? LocalDate.parse(req.body.expiryDate).atStartOfDay().format(formatter) : null + effectiveDate: req.body.effectiveDate ? req.body.effectiveDate : null, + expiryDate: req.body.expiryDate ? req.body.expiryDate : null }; const data = await utils.postData(token, url, payload, null, utils.getUser(req).idir_username); @@ -166,7 +165,6 @@ async function updateDistrict(req, res) { async function updateDistrictContact(req, res) { try { const token = getBackendToken(req); - const formatter = DateTimeFormatter.ofPattern('yyyy-MM-dd\'T\'HH:mm:ss'); let district = cacheService.getDistrictJSONByDistrictId(req.body.districtId); if(!district || !hasDistrictAdminRole(req)){ @@ -185,8 +183,6 @@ async function updateDistrictContact(req, res) { params.updateDate = null; params.createDate = null; params.updateUser = utils.getUser(req).idir_username; - params.effectiveDate = params.effectiveDate ? LocalDate.parse(req.body.effectiveDate).atStartOfDay().format(formatter) : null; - params.expiryDate = req.body.expiryDate ? LocalDate.parse(req.body.expiryDate).atStartOfDay().format(formatter) : null; const result = await utils.putData(token, `${config.get('server:institute:instituteDistrictURL')}/${req.body.districtId}/contact/${req.params.contactId}` , params, utils.getUser(req).idir_username); return res.status(HttpStatus.OK).json(result); @@ -199,7 +195,6 @@ async function updateDistrictContact(req, res) { async function deleteDistrictContact(req, res) { try { const token = getBackendToken(req); - const formatter = DateTimeFormatter.ofPattern('yyyy-MM-dd\'T\'HH:mm:ss'); let district = cacheService.getDistrictJSONByDistrictId(req.params.districtId); if(!district || !hasDistrictAdminRole(req)){ @@ -225,7 +220,7 @@ async function deleteDistrictContact(req, res) { contact.createDate = null; contact.updateDate = null; contact.updateUser = utils.getUser(req).idir_username; - contact.expiryDate = LocalDateTime.now().format(formatter); + contact.expiryDate = LocalDate.now().atStartOfDay().format(DateTimeFormatter.ofPattern('yyyy-MM-dd\'T\'HH:mm:ss')); await utils.putData(token, config.get('server:institute:instituteDistrictURL') + '/' + req.params.districtId + '/contact/'+ req.params.contactId , contact, utils.getUser(req).idir_username); @@ -347,8 +342,6 @@ async function addSchool(req, res) { }); } - const formatter = DateTimeFormatter.ofPattern('yyyy-MM-dd\'T\'HH:mm:ss'); - const payload = { createUser: utils.getUser(req).idir_username, createDate: null, @@ -366,7 +359,7 @@ async function addSchool(req, res) { schoolOrganizationCode: req.body.schoolOrganizationCode, schoolCategoryCode: req.body.schoolCategoryCode, facilityTypeCode: req.body.facilityTypeCode, - openedDate: req.body.openedDate ? LocalDate.parse(req.body.openedDate).atStartOfDay().format(formatter) : null, + openedDate: req.body.openedDate ? req.body.openedDate : null, closedDate: null, addresses: [], grades: [], @@ -496,7 +489,6 @@ async function deleteSchoolNote(req, res) { async function addSchoolContact(req, res) { try { const token = getBackendToken(req); - const formatter = DateTimeFormatter.ofPattern('yyyy-MM-dd\'T\'HH:mm:ss'); let school = cacheService.getSchoolBySchoolID(req.body.schoolID); if(!school || !hasSchoolAdminRole(req, school)){ @@ -523,8 +515,8 @@ async function addSchoolContact(req, res) { phoneExtension: req.body.phoneExtension, alternatePhoneNumber: req.body.alternatePhoneNumber, alternatePhoneExtension: req.body.alternatePhoneExtension, - effectiveDate: req.body.effectiveDate ? LocalDate.parse(req.body.effectiveDate).atStartOfDay().format(formatter) : null, - expiryDate: req.body.expiryDate ? LocalDate.parse(req.body.expiryDate).atStartOfDay().format(formatter) : null + effectiveDate: req.body.effectiveDate ? req.body.effectiveDate : null, + expiryDate: req.body.expiryDate ? req.body.expiryDate : null }; const data = await utils.postData(token, url, payload, null, utils.getUser(req).idir_username); @@ -539,7 +531,6 @@ async function addSchoolContact(req, res) { async function updateSchoolContact(req, res) { try { const token = getBackendToken(req); - const formatter = DateTimeFormatter.ofPattern('yyyy-MM-dd\'T\'HH:mm:ss'); let school = cacheService.getSchoolBySchoolID(req.body.schoolID); if(!school || !hasSchoolAdminRole(req, school)){ @@ -558,8 +549,9 @@ async function updateSchoolContact(req, res) { params.updateDate = null; params.createDate = null; params.updateUser = utils.getUser(req).idir_username; - params.effectiveDate = params.effectiveDate ? LocalDate.parse(req.body.effectiveDate).atStartOfDay().format(formatter) : null; - params.expiryDate = req.body.expiryDate ? LocalDate.parse(req.body.expiryDate).atStartOfDay().format(formatter) : null; + params.effectiveDate = params.effectiveDate ? req.body.effectiveDate : null; + params.expiryDate = req.body.expiryDate ? req.body.expiryDate : null; + params.expiryDate = req.body.expiryDate ? req.body.expiryDate : null; const result = await utils.putData(token, config.get('server:institute:instituteSchoolURL') + '/' + req.body.schoolID + '/contact/'+ req.params.contactId , params, utils.getUser(req).idir_username); return res.status(HttpStatus.OK).json(result); @@ -572,7 +564,6 @@ async function updateSchoolContact(req, res) { async function deleteSchoolContact(req, res) { try { const token = getBackendToken(req); - const formatter = DateTimeFormatter.ofPattern('yyyy-MM-dd\'T\'HH:mm:ss'); let school = cacheService.getSchoolBySchoolID(req.params.schoolId); if(!school || !hasSchoolAdminRole(req, school)){ @@ -598,7 +589,7 @@ async function deleteSchoolContact(req, res) { contact.createDate = null; contact.updateDate = null; contact.updateUser = utils.getUser(req).idir_username; - contact.expiryDate = LocalDateTime.now().format(formatter); + contact.expiryDate = LocalDate.now().atStartOfDay().format(DateTimeFormatter.ofPattern('yyyy-MM-dd\'T\'HH:mm:ss')); await utils.putData(token, config.get('server:institute:instituteSchoolURL') + '/' + req.params.schoolId + '/contact/'+ req.params.contactId , contact, utils.getUser(req).idir_username); @@ -612,7 +603,6 @@ async function deleteSchoolContact(req, res) { async function addAuthorityContact(req, res) { try { const token = getBackendToken(req); - const formatter = DateTimeFormatter.ofPattern('yyyy-MM-dd\'T\'HH:mm:ss'); let authority = cacheService.getAuthorityJSONByAuthorityId(req.body.authorityID); if(!authority || !hasAuthorityAdminRole(req, authority)){ @@ -639,8 +629,8 @@ async function addAuthorityContact(req, res) { phoneExtension: req.body.phoneExtension, alternatePhoneNumber: req.body.alternatePhoneNumber, alternatePhoneExtension: req.body.alternatePhoneExtension, - effectiveDate: req.body.effectiveDate ? LocalDate.parse(req.body.effectiveDate).atStartOfDay().format(formatter) : null, - expiryDate: req.body.expiryDate ? LocalDate.parse(req.body.expiryDate).atStartOfDay().format(formatter) : null + effectiveDate: req.body.effectiveDate ? req.body.effectiveDate : null, + expiryDate: req.body.expiryDate ? req.body.expiryDate : null }; const data = await utils.postData(token, url, payload, null, utils.getUser(req).idir_username); @@ -655,7 +645,6 @@ async function addAuthorityContact(req, res) { async function updateAuthorityContact(req, res) { try { const token = getBackendToken(req); - const formatter = DateTimeFormatter.ofPattern('yyyy-MM-dd\'T\'HH:mm:ss'); let authority = cacheService.getAuthorityJSONByAuthorityId(req.body.independentAuthorityId); if(!authority || !hasAuthorityAdminRole(req, authority)){ @@ -674,8 +663,6 @@ async function updateAuthorityContact(req, res) { params.updateDate = null; params.createDate = null; params.updateUser = utils.getUser(req).idir_username; - params.effectiveDate = params.effectiveDate ? LocalDate.parse(req.body.effectiveDate).atStartOfDay().format(formatter) : null; - params.expiryDate = req.body.expiryDate ? LocalDate.parse(req.body.expiryDate).atStartOfDay().format(formatter) : null; const result = await utils.putData(token, config.get('server:institute:instituteAuthorityURL') + '/' + req.body.independentAuthorityId + '/contact/'+ req.params.contactId , params, utils.getUser(req).idir_username); return res.status(HttpStatus.OK).json(result); @@ -688,7 +675,6 @@ async function updateAuthorityContact(req, res) { async function deleteAuthorityContact(req, res) { try { const token = getBackendToken(req); - const formatter = DateTimeFormatter.ofPattern('yyyy-MM-dd\'T\'HH:mm:ss'); let authority = cacheService.getAuthorityJSONByAuthorityId(req.params.independentAuthorityId); if(!authority || !hasAuthorityAdminRole(req, authority)){ @@ -714,7 +700,7 @@ async function deleteAuthorityContact(req, res) { contact.createDate = null; contact.updateDate = null; contact.updateUser = utils.getUser(req).idir_username; - contact.expiryDate = LocalDateTime.now().format(formatter); + contact.expiryDate = LocalDate.now().atStartOfDay().format(DateTimeFormatter.ofPattern('yyyy-MM-dd\'T\'HH:mm:ss')); await utils.putData(token, config.get('server:institute:instituteAuthorityURL') + '/' + req.params.independentAuthorityId + '/contact/'+ req.params.contactId , contact, utils.getUser(req).idir_username); @@ -728,7 +714,6 @@ async function deleteAuthorityContact(req, res) { async function addAuthority(req, res) { try { const token = getBackendToken(req); - const formatter = DateTimeFormatter.ofPattern('yyyy-MM-dd\'T\'HH:mm:ss'); if(!hasAuthorityAdminRole(req)){ return res.status(HttpStatus.UNAUTHORIZED).json({ @@ -742,7 +727,7 @@ async function addAuthority(req, res) { displayName: req.body.authorityName, authorityTypeCode: req.body.authorityTypeCode, - openedDate: req.body.openDate ? LocalDate.parse(req.body.openDate).atStartOfDay().format(formatter) : null, + openedDate: req.body.openDate ? req.body.openDate : null, email: req.body.email, phoneNumber: req.body.phoneNumber, faxNumber: req.body.faxNumber, @@ -991,7 +976,6 @@ async function getSchoolsPaginated(req, res){ async function moveSchool(req, res) { try { const token = getBackendToken(req); - const formatter = DateTimeFormatter.ofPattern('yyyy-MM-dd\'T\'HH:mm:ss'); if(!hasSchoolAdminRole(req, req.body.toSchool)){ return res.status(HttpStatus.UNAUTHORIZED).json({ @@ -1000,7 +984,7 @@ async function moveSchool(req, res) { } const incomingPayload = req.body; - incomingPayload.toSchool.openedDate = LocalDate.parse(incomingPayload.toSchool.moveDate).atStartOfDay().format(formatter); + incomingPayload.toSchool.openedDate = incomingPayload.toSchool.moveDate; incomingPayload.toSchool.createDate = null; incomingPayload.toSchool.updateDate = null; incomingPayload.toSchool.createUser = utils.getUser(req).idir_username; @@ -1055,7 +1039,7 @@ async function moveSchool(req, res) { const payload = { toSchool: incomingPayload.toSchool, - moveDate: LocalDate.parse(incomingPayload.toSchool.moveDate).atStartOfDay().format(formatter), + moveDate: incomingPayload.toSchool.moveDate, fromSchoolId: req.body.fromSchoolId }; diff --git a/backend/src/config/index.js b/backend/src/config/index.js index 8081c1c2f..18f7346cf 100644 --- a/backend/src/config/index.js +++ b/backend/src/config/index.js @@ -176,7 +176,8 @@ nconf.defaults({ frontendConfig: { bannerEnvironment: process.env.BANNER_ENVIRONMENT, bannerColor: process.env.BANNER_COLOR, - webSocketURL: process.env.WEB_SOCKET_URL + webSocketURL: process.env.WEB_SOCKET_URL, + disableSdcFunctionality: process.env.DISABLE_SDC_FUNCTIONALITY === 'true' }, sdc: { rootURL: process.env.SDC_API_URL, diff --git a/backend/src/routes/config.js b/backend/src/routes/config.js index 988c599eb..f8f121fc6 100644 --- a/backend/src/routes/config.js +++ b/backend/src/routes/config.js @@ -12,7 +12,8 @@ async function getConfig(req, res) { const frontConfig = { BANNER_ENVIRONMENT: frontendConfig.bannerEnvironment, BANNER_COLOR: frontendConfig.bannerColor, - WEB_SOCKET_URL: frontendConfig.webSocketURL + WEB_SOCKET_URL: frontendConfig.webSocketURL, + DISABLE_SDC_FUNCTIONALITY: frontendConfig.disableSdcFunctionality }; return res.status(HttpStatus.OK).json(frontConfig); } diff --git a/backend/src/server.js b/backend/src/server.js index 7fe11b6b8..e20a1e378 100644 --- a/backend/src/server.js +++ b/backend/src/server.js @@ -107,11 +107,13 @@ cacheService.loadDataToCache( constants.CACHE_KEYS.AUTHORITY_CONTACT_TYPES, 'ser }).catch((e) => { log.error('Error loading AUTHORITY_CONTACT_TYPES data during boot .', e); }); -cacheService.loadDataToCache( constants.CACHE_KEYS.SDC_FUNDING_GROUPS, 'sdc:fundingGroupsURL').then(() => { - log.info('Loaded FUNDING_GROUPS data to memory'); -}).catch((e) => { - log.error('Error loading FUNDING_GROUPS data during boot .', e); -}); +if(!config.get('frontendConfig').disableSdcFunctionality) { + cacheService.loadDataToCache( constants.CACHE_KEYS.SDC_FUNDING_GROUPS, 'sdc:fundingGroupsURL').then(() => { + log.info('Loaded FUNDING_GROUPS data to memory'); + }).catch((e) => { + log.error('Error loading FUNDING_GROUPS data during boot .', e); + }); +} cacheService.loadAllAuthoritiesToMap().then(() => { log.info('Loaded authorities data to memory'); diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 7d92530ac..ab20ac948 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -12,6 +12,7 @@ "@fortawesome/fontawesome-free": "6.4.0", "@js-joda/core": "^5.5.3", "@mdi/font": "^7.2.96", + "@vuepic/vue-datepicker": "^7.0.0", "axios": "^1.4.0", "chart.js": "^4.3.0", "chartjs-plugin-datalabels": "^2.2.0", @@ -43,7 +44,6 @@ "vue-meta": "^3.0.0-alpha.10", "vue-quick-chat": "^1.2.8", "vue-router": "^4.2.2", - "vue3-treeview": "^0.4.1", "vuetify": "npm:@vuetify/nightly@3.3.5-pr-17265.042d482" }, "devDependencies": { @@ -569,6 +569,22 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/runtime": { + "version": "7.23.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.1.tgz", + "integrity": "sha512-hC2v6p8ZSI/W0HUzh3V8C5g+NwSKzKPtJwSpTjwl0o297GP9+ZLQSkdvHz46CM3LqyoXxq+5G9komY+eSqSO0g==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime/node_modules/regenerator-runtime": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" + }, "node_modules/@babel/template": { "version": "7.22.5", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", @@ -2239,6 +2255,21 @@ "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.4.tgz", "integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==" }, + "node_modules/@vuepic/vue-datepicker": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@vuepic/vue-datepicker/-/vue-datepicker-7.0.0.tgz", + "integrity": "sha512-9qM5RsnjDDe82qQusEC4s+56yTEXj1Z0ZKV4k01u1v+BSr/eBySwlsEwRqObPpP/yehZ6oXdC2KGcERPyX0bnA==", + "dependencies": { + "date-fns": "^2.30.0", + "date-fns-tz": "^1.3.7" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "vue": ">=3.2.0" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", @@ -3097,6 +3128,29 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" }, + "node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/date-fns-tz": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/date-fns-tz/-/date-fns-tz-1.3.8.tgz", + "integrity": "sha512-qwNXUFtMHTTU6CFSFjoJ80W8Fzzp24LntbjFFBgL/faqds4e5mo9mftoRLgr3Vi1trISsg4awSpYVsOQCRnapQ==", + "peerDependencies": { + "date-fns": ">=2.0.0" + } + }, "node_modules/de-indent": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", @@ -6652,32 +6706,12 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "node_modules/lodash.eq": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/lodash.eq/-/lodash.eq-4.0.0.tgz", - "integrity": "sha512-vbrJpXL6kQNG6TkInxX12DZRfuYVllSxhwYqjYB78g2zF3UI15nFO/0AgmZnZRnaQ38sZtjCiVjGr2rnKt4v0g==" - }, - "node_modules/lodash.isnil": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz", - "integrity": "sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng==" - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "node_modules/lodash.tointeger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.tointeger/-/lodash.tointeger-4.0.4.tgz", - "integrity": "sha512-UQbTdxNHMm4jGlf+LtxB5ZPJFufuND2gZCYjMxSOUmcxfq350x9KnwL3EzxDDNth8fOZ9wpwDTGWZQnFgdV3gg==" - }, - "node_modules/lodash.uniqueid": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.uniqueid/-/lodash.uniqueid-4.0.1.tgz", - "integrity": "sha512-GQQWaIeGlL6DIIr06kj1j6sSmBxyNMwI8kaX9aKpHR/XsMTiaXDVPNPAkiboOTK9OJpTJF/dXT3xYoFQnj386Q==" - }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -8420,18 +8454,6 @@ "he": "^1.2.0" } }, - "node_modules/vue3-treeview": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/vue3-treeview/-/vue3-treeview-0.4.1.tgz", - "integrity": "sha512-IUQN9Gzqxr66Qc6l+Js+ZBo57q5dHmiyD6FBRdt2WRnmMZ+wRtZ2UuwdLMiuGBT6gOVEzL7ucLIZGPZyKyyI4g==", - "dependencies": { - "lodash.eq": "^4.0.0", - "lodash.isnil": "^4.0.0", - "lodash.tointeger": "^4.0.4", - "lodash.uniqueid": "^4.0.1", - "vue": "^3.1.2" - } - }, "node_modules/vuetify": { "name": "@vuetify/nightly", "version": "3.3.5-pr-17265.042d482", @@ -9056,6 +9078,21 @@ "@babel/helper-plugin-utils": "^7.19.0" } }, + "@babel/runtime": { + "version": "7.23.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.1.tgz", + "integrity": "sha512-hC2v6p8ZSI/W0HUzh3V8C5g+NwSKzKPtJwSpTjwl0o297GP9+ZLQSkdvHz46CM3LqyoXxq+5G9komY+eSqSO0g==", + "requires": { + "regenerator-runtime": "^0.14.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" + } + } + }, "@babel/template": { "version": "7.22.5", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", @@ -10270,6 +10307,15 @@ "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.4.tgz", "integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==" }, + "@vuepic/vue-datepicker": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@vuepic/vue-datepicker/-/vue-datepicker-7.0.0.tgz", + "integrity": "sha512-9qM5RsnjDDe82qQusEC4s+56yTEXj1Z0ZKV4k01u1v+BSr/eBySwlsEwRqObPpP/yehZ6oXdC2KGcERPyX0bnA==", + "requires": { + "date-fns": "^2.30.0", + "date-fns-tz": "^1.3.7" + } + }, "@webassemblyjs/ast": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", @@ -10929,6 +10975,20 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" }, + "date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "requires": { + "@babel/runtime": "^7.21.0" + } + }, + "date-fns-tz": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/date-fns-tz/-/date-fns-tz-1.3.8.tgz", + "integrity": "sha512-qwNXUFtMHTTU6CFSFjoJ80W8Fzzp24LntbjFFBgL/faqds4e5mo9mftoRLgr3Vi1trISsg4awSpYVsOQCRnapQ==", + "requires": {} + }, "de-indent": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", @@ -13557,32 +13617,12 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "lodash.eq": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/lodash.eq/-/lodash.eq-4.0.0.tgz", - "integrity": "sha512-vbrJpXL6kQNG6TkInxX12DZRfuYVllSxhwYqjYB78g2zF3UI15nFO/0AgmZnZRnaQ38sZtjCiVjGr2rnKt4v0g==" - }, - "lodash.isnil": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz", - "integrity": "sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng==" - }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "lodash.tointeger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.tointeger/-/lodash.tointeger-4.0.4.tgz", - "integrity": "sha512-UQbTdxNHMm4jGlf+LtxB5ZPJFufuND2gZCYjMxSOUmcxfq350x9KnwL3EzxDDNth8fOZ9wpwDTGWZQnFgdV3gg==" - }, - "lodash.uniqueid": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.uniqueid/-/lodash.uniqueid-4.0.1.tgz", - "integrity": "sha512-GQQWaIeGlL6DIIr06kj1j6sSmBxyNMwI8kaX9aKpHR/XsMTiaXDVPNPAkiboOTK9OJpTJF/dXT3xYoFQnj386Q==" - }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -14756,18 +14796,6 @@ "he": "^1.2.0" } }, - "vue3-treeview": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/vue3-treeview/-/vue3-treeview-0.4.1.tgz", - "integrity": "sha512-IUQN9Gzqxr66Qc6l+Js+ZBo57q5dHmiyD6FBRdt2WRnmMZ+wRtZ2UuwdLMiuGBT6gOVEzL7ucLIZGPZyKyyI4g==", - "requires": { - "lodash.eq": "^4.0.0", - "lodash.isnil": "^4.0.0", - "lodash.tointeger": "^4.0.4", - "lodash.uniqueid": "^4.0.1", - "vue": "^3.1.2" - } - }, "vuetify": { "version": "npm:@vuetify/nightly@3.3.5-pr-17265.042d482", "resolved": "https://registry.npmjs.org/@vuetify/nightly/-/nightly-3.3.5-pr-17265.042d482.tgz", diff --git a/frontend/package.json b/frontend/package.json index 73ee26b31..3acf44819 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -13,6 +13,7 @@ "@fortawesome/fontawesome-free": "6.4.0", "@js-joda/core": "^5.5.3", "@mdi/font": "^7.2.96", + "@vuepic/vue-datepicker": "^7.0.0", "axios": "^1.4.0", "chart.js": "^4.3.0", "chartjs-plugin-datalabels": "^2.2.0", diff --git a/frontend/src/App.vue b/frontend/src/App.vue index f6d1065ec..1b5e817b2 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -193,4 +193,7 @@ export default { background-color: rgba(0,0,0,.12)!important; } + .viewer-open { + padding-right: 0 !important; + } diff --git a/frontend/src/components/institute/AuthoritiesList.vue b/frontend/src/components/institute/AuthoritiesList.vue index 74670b73e..7a814f93b 100644 --- a/frontend/src/components/institute/AuthoritiesList.vue +++ b/frontend/src/components/institute/AuthoritiesList.vue @@ -148,7 +148,7 @@ v-model:items="authorities" v-model:items-length="totalAuthorities" :loading="loadingTable" - class="elevation-1" + class="elevation-1 rounded" hide-default-header mobile-breakpoint="0" > @@ -210,31 +210,8 @@ formatPhoneNumber(item.raw.phoneNumber) }} - - - - View Contacts - - + @@ -809,25 +151,24 @@ import ApiService from '../../common/apiService'; import {Routes} from '@/utils/constants'; import alertMixin from '@/mixins/alertMixin'; -import PrimaryButton from '@/components/util/PrimaryButton.vue'; import {formatPhoneNumber, formatDate} from '@/utils/format'; import {getStatusColorAuthorityOrSchool, getStatusAuthorityOrSchool} from '@/utils/institute/status'; import {mapState} from 'pinia'; import router from '@/router'; import {deepCloneObject} from '@/utils/common'; import * as Rules from '@/utils/institute/formRules'; -import AuthorityStatus from '@/components/institute/AuthorityStatus.vue'; -import {isEmpty, omitBy} from 'lodash'; import {authStore} from '@/store/modules/auth'; import {instituteStore} from '@/store/modules/institute'; +import Details from './authority/Details.vue'; +import AuthorityContacts from './authority/AuthoritiesContacts.vue'; import InstituteNotes from '@/components/institute/common/InstituteNotes.vue'; export default { name: 'AuthorityDetailsPage', components: { - InstituteNotes, - AuthorityStatus, - PrimaryButton + Details, + AuthorityContacts, + InstituteNotes }, mixins: [alertMixin], props: { @@ -854,6 +195,7 @@ export default { countryCodeValues: [], listOfOpenSchools: [], listOfClosingSchools: [], + tab: null, excludeShowingPhysicalAddressesForAuthoritiesOfType: [ 'OFFSHORE', ], @@ -888,8 +230,6 @@ export default { this.authorityTypes = this.authorityTypeCodes; }); this.getAuthority(); - this.determineIfAuthorityHasAnyOpenSchools(); - this.findClosedDateOfLastClosingSchool(); }, methods: { formatPhoneNumber, @@ -899,17 +239,8 @@ export default { authority.status = getStatusAuthorityOrSchool(authority); authority.type = this.getAuthorityType(authority); }, - isNumber: function (evt) { - let charCode = (evt.which) ? evt.which : evt.keyCode; - if ((charCode > 31 && (charCode < 48 || charCode > 57)) && charCode !== 46) { - evt.preventDefault(); - } else { - return true; - } - }, getAuthority() { this.loading = true; - ApiService.apiAxios.get(Routes.institute.AUTHORITY_DATA_URL + '/' + this.authorityID, {}).then(response => { this.authority = response.data; this.populateExtraAuthorityFields(this.authority); @@ -920,104 +251,10 @@ export default { this.loading = false; }); }, - determineIfAuthorityHasAnyOpenSchools() { - this.loading = true; - ApiService.apiAxios.get(Routes.institute.SCHOOL_PAGINATED_DATA_URL, { - params: { - pageNumber: 0, - pageSize: 100, - searchParams: omitBy({ - status: 'isOpenOrOpening', - authorityID: this.authorityID, - }, isEmpty), - } - }).then(response => { - this.listOfOpenSchools = response.data.content; - this.authorityHasOpenSchools = response.data.content.length > 0; - }).catch(error => { - console.error(error); - this.setFailureAlert(error?.response?.data?.message ? error?.response?.data?.message : 'An error occurred while trying to determine if the authority has any open schools. Please try again later.'); - }).finally(() => { - this.loading = false; - }); - }, - cancelEdit() { - this.editing = !this.editing; - this.setHasSamePhysicalFlag(); - }, - findClosedDateOfLastClosingSchool() { - this.loading = true; - ApiService.apiAxios.get(Routes.institute.SCHOOL_PAGINATED_DATA_URL, { - params: { - pageNumber: 0, - pageSize: 100, - sort: { - closedDate: 'DESC' - }, - searchParams: omitBy({ - authorityID: this.authorityID, - status: 'Closing' - }, isEmpty), - } - }).then(response => { - this.listOfClosingSchools = response.data.content; - this.closedDateOfLastClosingSchool = response.data.content[0] ? response.data.content[0].closedDate.substring(0, 10) : null; - }).catch(error => { - console.error(error); - this.setFailureAlert(error?.response?.data?.message ? error?.response?.data?.message : 'An error occurred while trying to find the closed date of the last closing school. Please try again later.'); - }).finally(() => { - this.loading = false; - }); - }, backButtonClick() { router.push({name: 'instituteAuthoritiesList'}); }, deepCloneObject, - addAddressesIfRequired(authority) { - let addresses = authority?.addresses; - if (!this.hasMailingAddress()) { - addresses.push({ - 'createUser': null, - 'updateUser': null, - 'createDate': null, - 'updateDate': null, - 'addressId': null, - 'schoolId': null, - 'districtId': null, - 'independentAuthorityId': null, - 'phoneNumber': null, - 'email': null, - 'addressLine1': null, - 'addressLine2': null, - 'city': null, - 'postal': null, - 'addressTypeCode': 'MAILING', - 'provinceCode': null, - 'countryCode': null - }); - } - if (!this.hasPhysicalAddress()) { - addresses.push({ - 'createUser': null, - 'updateUser': null, - 'createDate': null, - 'updateDate': null, - 'addressId': null, - 'schoolId': null, - 'districtId': null, - 'independentAuthorityId': null, - 'phoneNumber': null, - 'email': null, - 'addressLine1': null, - 'addressLine2': null, - 'city': null, - 'postal': null, - 'addressTypeCode': 'PHYSICAL', - 'provinceCode': null, - 'countryCode': null - }); - } - }, canEditAuthorities() { if(this.authority?.authorityTypeCode && this.authority?.authorityTypeCode === 'INDEPENDNT') { return this.INDEPENDENT_AUTHORITY_ADMIN_ROLE || this.INDEPENDENT_SCHOOLS_ADMIN_ROLE; @@ -1036,15 +273,10 @@ export default { showEditLinks(fieldValue) { return this.canEditAuthorities() && !fieldValue; }, - saveAuthority() { + saveAuthority(authorityCopy) { this.loading = true; - - if (this.sameAsMailingCheckbox) { - this.authorityCopy.addresses = this.authorityCopy.addresses.filter(address => address.addressTypeCode === 'MAILING'); - } - - const payload = this.authorityCopy; - ApiService.apiAxios.post(`${Routes.institute.AUTHORITY_DATA_URL}` + '/' + this.authorityCopy.independentAuthorityId, payload) + const payload = authorityCopy; + ApiService.apiAxios.post(`${Routes.institute.AUTHORITY_DATA_URL}` + '/' + authorityCopy.independentAuthorityId, payload) .then(() => { this.setSuccessAlert('Success! The authority details have been updated.'); }) @@ -1053,72 +285,13 @@ export default { this.setFailureAlert(error?.response?.data?.message ? error?.response?.data?.message : 'An error occurred while saving the authority information. Please try again later.'); }) .finally(() => { - this.toggleEdit(); this.getAuthority(); }); }, - async toggleEdit() { - this.authorityCopy = this.deepCloneObject(this.authority); - this.addAddressesIfRequired(this.authorityCopy); - this.editing = !this.editing; - await this.$nextTick(); - await this.$refs.authorityForm.validate(); - }, + getAuthorityType(authority) { return this.authorityTypes.find((autorityType) => autorityType.authorityTypeCode === authority?.authorityTypeCode).label; }, - hasMailingAddress() { - return this.authority?.addresses.filter(address => address.addressTypeCode === 'MAILING').length > 0; - }, - hasPhysicalAddress() { - return this.authority?.addresses.filter(address => address.addressTypeCode === 'PHYSICAL').length > 0; - }, - getMailingAddress() { - return this.authority?.addresses.filter(address => address.addressTypeCode === 'MAILING'); - }, - getPhysicalAddress() { - return this.authority?.addresses.filter(address => address.addressTypeCode === 'PHYSICAL'); - }, - getMailingAddressCopy() { - return this.authorityCopy.addresses.filter(address => address.addressTypeCode === 'MAILING'); - }, - getPhysicalAddressCopy() { - return this.authorityCopy.addresses.filter(address => address.addressTypeCode === 'PHYSICAL'); - }, - getMailingAddressItem(item) { - let mailingAddress = this.authority?.addresses.filter(address => address.addressTypeCode === 'MAILING'); - for (const x in mailingAddress[0]) { - if (x === item) { - return mailingAddress[0][item]; - } - } - }, - getPhysicalAddressItem(item) { - let physicalAddress = this.authority?.addresses.filter(address => address.addressTypeCode === 'PHYSICAL'); - for (const x in physicalAddress[0]) { - if (x === item) { - return physicalAddress[0][item]; - } - } - }, - openAuthorityStatusEdit() { - this.openAuthorityStatusEditCard = true; - }, - async handleUpdatesToAuthorityStatus(updatedDatesForAuthority) { - await this.$nextTick(); - if (updatedDatesForAuthority.openedDate) { - this.authorityCopy.openedDate = updatedDatesForAuthority.openedDate?.replaceAll('/', '-').concat('T00:00:00'); - } else { - this.authorityCopy.openedDate = null; - } - if (updatedDatesForAuthority.closedDate) { - this.authorityCopy.closedDate = updatedDatesForAuthority.closedDate?.replaceAll('/', '-').concat('T00:00:00'); - } else { - this.authorityCopy.closedDate = null; - } - this.authorityCopy.status = getStatusAuthorityOrSchool(this.authorityCopy); - this.$refs.authorityForm.validate(); - }, saveNewAuthorityNote(authorityNote) { this.noteRequestCount += 1; const payload = { @@ -1190,8 +363,8 @@ export default { } .containerSetup { - padding-right: 24em !important; - padding-left: 24em !important; + padding-right: 20em !important; + padding-left: 20em !important; } .editField { @@ -1203,5 +376,24 @@ export default { text-decoration: underline; } +.v-tab { + text-transform: none !important; + font-size: 16px; + font-weight: bold; +} + +.tab-divider { + border-right: 1px solid lightgray; + border-radius: 0; +} + +.tab-divider:last-child { + border-right: 0 +} + +:deep(.v-btn--variant-text) { + color: #003366 +} + diff --git a/frontend/src/components/institute/AuthorityStatus.vue b/frontend/src/components/institute/AuthorityStatus.vue index ce491245a..a89d6090a 100644 --- a/frontend/src/components/institute/AuthorityStatus.vue +++ b/frontend/src/components/institute/AuthorityStatus.vue @@ -55,15 +55,13 @@ - @@ -104,8 +102,9 @@ v-if="showAlertForFutureClosureDate" color="#003366" density="compact" - text type="info" + class="px-2" + variant="tonal" >

Some schools under this authority have closing dates in the future.

@@ -132,23 +131,20 @@

Refresh the page to see an updated list of schools.

- +

Select the closure date

- @@ -164,8 +160,9 @@ v-if="showAlertForFutureClosureDate" color="#003366" density="compact" - text type="info" + class="px-2" + variant="tonal" >

Some schools under this authority have closing dates in the future.

@@ -192,23 +189,20 @@

Refresh the page to see an updated list of schools.

- +

Select the new closing date

- @@ -229,9 +223,9 @@ id="newContactPostBtn" text="Okay" width="7rem" - @click-action="updateAuthorityDates" :disabled="!isFormValid" :loading="processing" + @click-action="updateAuthorityDates" /> @@ -243,12 +237,13 @@ import PrimaryButton from '../util/PrimaryButton.vue'; import alertMixin from '@/mixins/alertMixin'; import * as Rules from '@/utils/institute/formRules'; import {formatDate, formatDisplayDate} from '@/utils/format'; -import {parseDate} from '@/utils/dateHelpers'; -import {LocalDate} from '@js-joda/core'; +import {DateTimeFormatter, LocalDate, LocalDateTime} from '@js-joda/core'; +import DatePicker from '@/components/util/DatePicker.vue'; export default { name: 'AuthorityStatus', components: { + DatePicker, PrimaryButton, }, mixins: [alertMixin], @@ -283,16 +278,17 @@ export default { } }, data() { - let currentLocalDate = LocalDate.now().toString(); + let currentLocalDate = LocalDate.now(); return { - currentDate: currentLocalDate, + currentDate: currentLocalDate.toString(), + cutOffDate: currentLocalDate.plusDays(1).toString(), isFormValid: false, processing: false, rules: Rules, action: this.defaultUpdateActionForAuthority(), - newOpenDate: currentLocalDate, + newOpenDate: currentLocalDate.atStartOfDay().format(DateTimeFormatter.ofPattern('yyyy-MM-dd\'T\'HH:mm:ss')), newCloseDate: null, - updatedCloseDate: this.parseDate(formatDate(this.authorityCloseDate)) + updatedCloseDate: this.authorityCloseDate }; }, computed: { @@ -318,37 +314,13 @@ export default { if (!this.dateOfLastSchoolClosure) { return ''; } - return this.formatDisplayDate(this.dateOfLastSchoolClosure); + return this.formatDate(this.dateOfLastSchoolClosure); }, showAlertForFutureClosureDate() { if (!this.dateOfLastSchoolClosure) { return false; } - return LocalDate.now().isBefore(LocalDate.parse(this.dateOfLastSchoolClosure)); - }, - newOpenDateFormatted: { - get() { - return this.formatDisplayDate(this.newOpenDate); - }, - set(newValue) { - this.newOpenDate = this.parseDate(newValue); - } - }, - newCloseDateFormatted: { - get() { - return this.formatDisplayDate(this.newCloseDate); - }, - set(newValue) { - this.newCloseDate = this.parseDate(newValue); - } - }, - updatedCloseDateFormatted: { - get() { - return this.formatDisplayDate(this.updatedCloseDate); - }, - set(newValue) { - this.updatedCloseDate = this.parseDate(newValue); - } + return LocalDateTime.now().isBefore(LocalDateTime.parse(this.dateOfLastSchoolClosure)); }, listOfOpenSchoolsByMincode() { return [...this.listOfOpenSchools].sort((schoolA, schoolB) => { @@ -361,24 +333,6 @@ export default { }); }, }, - watch: { - //watching effective date to valid form because we need to cross validate expiry and effective date fields - 'newOpenDate': { - handler() { - this.validateForm(); - } - }, - 'newCloseDate': { - handler() { - this.validateForm(); - } - }, - 'updatedCloseDate': { - handler() { - this.validateForm(); - } - } - }, mounted() { this.validateForm(); }, @@ -394,15 +348,6 @@ export default { return ''; } }, - saveNewOpenDate(date) { - this.$refs.newOpenDateFilter.save(date); - }, - saveNewCloseDate(date) { - this.$refs.newCloseDateFilter.save(date); - }, - saveUpdatedCloseDate(date) { - this.$refs.updatedCloseDateFilter.save(date); - }, closeEditAuthorityStatus() { this.resetForm(); this.$emit('authorityStatus:closeEditAuthorityStatusPage'); @@ -416,20 +361,20 @@ export default { switch (this.action) { case 'setOpenDate': updatedAuthorityDates = { - openedDate: this.newOpenDateFormatted, + openedDate: this.newOpenDate, closedDate: null, }; break; case 'setCloseDate': updatedAuthorityDates = { - openedDate: this.parseDate(formatDate(this.authorityOpenDate)), - closedDate: this.newCloseDateFormatted + openedDate: this.authorityOpenDate, + closedDate: this.newCloseDate }; break; case 'updateCloseDate': updatedAuthorityDates = { - openedDate: this.parseDate(formatDate(this.authorityOpenDate)), - closedDate: this.updatedCloseDateFormatted, + openedDate: this.authorityOpenDate, + closedDate: this.updatedCloseDate, }; break; default: @@ -451,8 +396,7 @@ export default { this.isFormValid = isValid.valid; }, formatDate, - formatDisplayDate, - parseDate + formatDisplayDate } }; diff --git a/frontend/src/components/institute/DistrictDetails.vue b/frontend/src/components/institute/DistrictDetails.vue index 053d164b2..29add1530 100644 --- a/frontend/src/components/institute/DistrictDetails.vue +++ b/frontend/src/components/institute/DistrictDetails.vue @@ -1,719 +1,162 @@ diff --git a/frontend/src/components/institute/AuthoritiesContacts.vue b/frontend/src/components/institute/authority/AuthoritiesContacts.vue similarity index 86% rename from frontend/src/components/institute/AuthoritiesContacts.vue rename to frontend/src/components/institute/authority/AuthoritiesContacts.vue index c23c180b1..34abdf3a7 100644 --- a/frontend/src/components/institute/AuthoritiesContacts.vue +++ b/frontend/src/components/institute/authority/AuthoritiesContacts.vue @@ -1,6 +1,5 @@ diff --git a/frontend/src/components/institute/common/Details.vue b/frontend/src/components/institute/common/Details.vue index aabe5e863..cee7e1ca2 100644 --- a/frontend/src/components/institute/common/Details.vue +++ b/frontend/src/components/institute/common/Details.vue @@ -762,7 +762,7 @@ > mdi-email-outline - Mailing Address + Mailing Address @@ -781,21 +781,21 @@ - + {{ getMailingAddressItem('addressLine2') }} - + {{ getMailingAddressItem('city') + ', ' + getMailingAddressItem('provinceCode') + ', ' + getMailingAddressItem('countryCode') }} - + {{ getMailingAddressItem('postal') }} @@ -816,7 +816,7 @@ > mdi-home-outline - Physical Address + Physical Address - + {{ getPhysicalAddressItem('addressLine1') }} - + {{ getPhysicalAddressItem('addressLine2') }} - + {{ getPhysicalAddressItem('city') + ', ' + getPhysicalAddressItem('provinceCode') + ', ' + getPhysicalAddressItem('countryCode') }} - + {{ getPhysicalAddressItem('postal') }} @@ -1589,12 +1589,12 @@ export default { async handleUpdatesToSchoolStatus(updatedDatesForSchool) { await this.$nextTick(); if (updatedDatesForSchool.openedDate) { - this.schoolDetailsCopy.openedDate = updatedDatesForSchool.openedDate?.replaceAll('/', '-').concat('T00:00:00'); + this.schoolDetailsCopy.openedDate = updatedDatesForSchool.openedDate; } else { this.schoolDetailsCopy.openedDate = null; } if (updatedDatesForSchool.closedDate) { - this.schoolDetailsCopy.closedDate = updatedDatesForSchool.closedDate?.replaceAll('/', '-').concat('T00:00:00'); + this.schoolDetailsCopy.closedDate = updatedDatesForSchool.closedDate; } else { this.schoolDetailsCopy.closedDate = null; } diff --git a/frontend/src/components/institute/common/EditSchoolContactPage.vue b/frontend/src/components/institute/common/EditSchoolContactPage.vue index a565dcefe..b8a592313 100644 --- a/frontend/src/components/institute/common/EditSchoolContactPage.vue +++ b/frontend/src/components/institute/common/EditSchoolContactPage.vue @@ -112,28 +112,25 @@ - - @@ -152,9 +149,9 @@ id="saveChangesToSchoolContactButton" text="Save" width="7rem" - @click-action="saveChangesToSchoolContact" :disabled="!isFormValid" :loading="processing" + @click-action="saveChangesToSchoolContact" /> @@ -168,14 +165,14 @@ import ApiService from '@/common/apiService'; import {Routes} from '@/utils/constants'; import * as Rules from '@/utils/institute/formRules'; import {isNumber} from '@/utils/institute/formInput'; -import {formatDate, formatDisplayDate} from '@/utils/format'; -import {parseDate} from '@/utils/dateHelpers'; import {authStore} from '@/store/modules/auth'; import _ from 'lodash'; +import DatePicker from '@/components/util/DatePicker.vue'; export default { name: 'EditSchoolContactPage', components: { + DatePicker, PrimaryButton, }, mixins: [alertMixin], @@ -193,42 +190,32 @@ export default { required: true } }, + emits: ['editSchoolContact:editSchoolContactSuccess', 'editSchoolContact:cancelEditSchoolContactPage'], data() { let clonedContact = _.cloneDeep(this.contact); - clonedContact.effectiveDate = this.parseDate(formatDate(clonedContact.effectiveDate)); - clonedContact.expiryDate = this.parseDate(formatDate(clonedContact.expiryDate)); return { isFormValid: false, processing: false, editContact: clonedContact, - rules: Rules, - editSchoolContactEffectiveDatePicker: null, - editSchoolContactExpiryDatePicker: null + rules: Rules }; }, - mounted() { - this.validateForm(); - }, computed: { ...mapState(authStore, ['isAuthenticated', 'userInfo']), - schoolContactEffectiveDateFormatted: { - get() { - return this.formatDisplayDate(this.editContact.effectiveDate); - }, - set(newValue) { - this.editContact.effectiveDate = this.parseDate(newValue); - } - }, - schoolContactExpiryDateFormatted: { - get() { - return this.formatDisplayDate(this.editContact.expiryDate); - }, - set(newValue) { - this.editContact.expiryDate = this.parseDate(newValue); - } - } + }, + + mounted() { + this.validateForm(); }, methods: { + clearEffectiveDate() { + this.editContact.effectiveDate = null; + this.validateForm(); + }, + clearExpiryDate() { + this.editContact.expiryDate = null; + this.validateForm(); + }, cancelEditSchoolContactPage() { this.resetForm(); this.$emit('editSchoolContact:cancelEditSchoolContactPage'); @@ -253,9 +240,6 @@ export default { this.processing = false; }); }, - saveEditSchoolContactExpiryDate(date) { - this.$refs.editSchoolContactExpiryDateFilter.save(date); - }, resetForm() { this.$refs.editSchoolContactForm.reset(); }, @@ -265,18 +249,7 @@ export default { this.isFormValid = isValid.valid; } }, - isNumber, - formatDate, - formatDisplayDate, - parseDate - }, - watch: { - //watching effective date to valid form because we need to cross validate expiry and effective date fields - 'editContact.effectiveDate': { - handler() { - this.validateForm(); - } - } + isNumber } }; diff --git a/frontend/src/components/institute/common/NewSchoolContactPage.vue b/frontend/src/components/institute/common/NewSchoolContactPage.vue index 91b8b21ea..d4323c109 100644 --- a/frontend/src/components/institute/common/NewSchoolContactPage.vue +++ b/frontend/src/components/institute/common/NewSchoolContactPage.vue @@ -112,28 +112,22 @@ - - @@ -153,9 +147,9 @@ id="newContactPostBtn" text="Save" width="7rem" - @click-action="addNewSchoolContact" :disabled="!isFormValid" :loading="processing" + @click-action="addNewSchoolContact" /> @@ -169,12 +163,14 @@ import ApiService from '@/common/apiService'; import {Routes} from '@/utils/constants'; import * as Rules from '@/utils/institute/formRules'; import {isNumber} from '@/utils/institute/formInput'; -import {LocalDate} from '@js-joda/core'; +import {DateTimeFormatter, LocalDate} from '@js-joda/core'; import {authStore} from '@/store/modules/auth'; +import DatePicker from '@/components/util/DatePicker.vue'; export default { name: 'NewSchoolContactPage', components: { + DatePicker, PrimaryButton, }, mixins: [alertMixin], @@ -202,27 +198,19 @@ export default { phoneExtension: null, alternatePhoneNumber: null, alternatePhoneExtension: null, - effectiveDate: LocalDate.now().toString(), + effectiveDate: LocalDate.now().atStartOfDay().format(DateTimeFormatter.ofPattern('yyyy-MM-dd\'T\'HH:mm:ss')).toString(), expiryDate: null }, - rules: Rules, - newContactEffectiveDatePicker: null, - newContactExpiryDatePicker: null + rules: Rules }; }, - mounted() { - this.validateForm(); - }, computed: { ...mapState(authStore, ['isAuthenticated', 'userInfo']), }, + mounted() { + this.validateForm(); + }, methods: { - saveNewContactEffectiveDate(date) { - this.$refs.newContactEffectiveDateFilter.save(date); - }, - saveNewContactExpiryDate(date) { - this.$refs.newContactExpiryDateFilter.save(date); - }, closeNewContactPage() { this.resetForm(); this.$emit('newSchoolContact:closeNewSchoolContactPage'); @@ -253,14 +241,6 @@ export default { this.isFormValid = isValid.valid; }, isNumber, - }, - watch: { - //watching effective date to valid form because we need to cross validate expiry and effective date fields - 'newContact.effectiveDate': { - handler() { - this.validateForm(); - } - } } }; diff --git a/frontend/src/components/institute/common/SchoolContacts.vue b/frontend/src/components/institute/common/SchoolContacts.vue index 5cd80a58c..4771d1d5d 100644 --- a/frontend/src/components/institute/common/SchoolContacts.vue +++ b/frontend/src/components/institute/common/SchoolContacts.vue @@ -46,9 +46,10 @@
- +

{{ schoolContactType.label @@ -60,7 +61,10 @@ v-if="!schoolContactType.publiclyAvailable" cols="2" > - + @@ -96,7 +101,7 @@ v-else cols="2" > - +

No contacts of this type have been listed.

diff --git a/frontend/src/components/institute/district/Details.vue b/frontend/src/components/institute/district/Details.vue new file mode 100644 index 000000000..4977deb75 --- /dev/null +++ b/frontend/src/components/institute/district/Details.vue @@ -0,0 +1,936 @@ + + + + + diff --git a/frontend/src/components/institute/DistrictContact.vue b/frontend/src/components/institute/district/DistrictContact.vue similarity index 100% rename from frontend/src/components/institute/DistrictContact.vue rename to frontend/src/components/institute/district/DistrictContact.vue diff --git a/frontend/src/components/institute/DistrictContacts.vue b/frontend/src/components/institute/district/DistrictContacts.vue similarity index 88% rename from frontend/src/components/institute/DistrictContacts.vue rename to frontend/src/components/institute/district/DistrictContacts.vue index 87847b9d9..81889d47e 100644 --- a/frontend/src/components/institute/DistrictContacts.vue +++ b/frontend/src/components/institute/district/DistrictContacts.vue @@ -1,20 +1,7 @@