From 7ca42ff27ee23caa0dce775a9e172c165e80f26d Mon Sep 17 00:00:00 2001 From: mgtennant <100305096+mgtennant@users.noreply.github.com> Date: Tue, 23 Jan 2024 15:52:21 -0800 Subject: [PATCH 1/9] add prettier config & fix nfr legal desc issue --- .prettierrc.json | 7 + frontend/src/report/report.service.ts | 388 ++++++++++---------------- 2 files changed, 157 insertions(+), 238 deletions(-) create mode 100644 .prettierrc.json diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 00000000..fc56e314 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,7 @@ +{ + "trailingComma": "es5", + "tabWidth": 2, + "semi": true, + "singleQuote": true, + "printWidth": 120 +} diff --git a/frontend/src/report/report.service.ts b/frontend/src/report/report.service.ts index 95b7019b..f5a23137 100644 --- a/frontend/src/report/report.service.ts +++ b/frontend/src/report/report.service.ts @@ -1,22 +1,11 @@ -import { HttpService } from "@nestjs/axios"; -import { Injectable } from "@nestjs/common"; -import * as dotenv from "dotenv"; -import { firstValueFrom } from "rxjs"; -import { TTLSService } from "src/ttls/ttls.service"; -import { - GL_REPORT_TYPE, - LUR_REPORT_TYPE, - numberWords, - sectionTitles, -} from "utils/constants"; -import { ProvisionJSON, VariableJSON } from "utils/types"; -import { - convertToSpecialCamelCase, - formatMoney, - grazingLeaseVariables, - nfrAddressBuilder, -} from "utils/util"; -const axios = require("axios"); +import { Injectable } from '@nestjs/common'; +import * as dotenv from 'dotenv'; +import { firstValueFrom } from 'rxjs'; +import { TTLSService } from 'src/ttls/ttls.service'; +import { GL_REPORT_TYPE, LUR_REPORT_TYPE, numberWords, sectionTitles } from 'utils/constants'; +import { ProvisionJSON, VariableJSON } from 'utils/types'; +import { convertToSpecialCamelCase, formatMoney, grazingLeaseVariables, nfrAddressBuilder } from 'utils/util'; +const axios = require('axios'); dotenv.config(); let hostname: string; @@ -24,12 +13,8 @@ let port: number; @Injectable() export class ReportService { - constructor( - private readonly ttlsService: TTLSService - ) { - hostname = process.env.backend_url - ? process.env.backend_url - : `http://localhost`; + constructor(private readonly ttlsService: TTLSService) { + hostname = process.env.backend_url ? process.env.backend_url : `http://localhost`; // local development backend port is 3001, docker backend port is 3000 port = process.env.backend_url ? 3000 : 3001; } @@ -42,19 +27,21 @@ export class ReportService { * @param tenureFileNumber * @returns */ - async generateReportName(dtid: number, tenureFileNumber: string, documentType:string) { + async generateReportName(dtid: number, tenureFileNumber: string, documentType: string) { const url = `${hostname}:${port}/print-request-log/version/${dtid}/${documentType}`; // grab the next version string for the dtid const version = await axios .get(url, { headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json', }, }) .then((res) => { return res.data; }); - return { reportName: documentType + "_" + tenureFileNumber + "_" + version }; + return { + reportName: documentType + '_' + tenureFileNumber + '_' + version, + }; } /** @@ -74,7 +61,7 @@ export class ReportService { const data = await axios .get(url, { headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json', }, }) .then((res) => { @@ -82,16 +69,12 @@ export class ReportService { }); if (data.InspectionDate) { - data["InspectionDate"] = this.ttlsService.formatInspectedDate( - data.InspectionDate - ); + data['InspectionDate'] = this.ttlsService.formatInspectedDate(data.InspectionDate); } // get the document template - const documentTemplateObject: { id: number; the_file: string } = await axios - .get(templateUrl) - .then((res) => { - return res.data; - }); + const documentTemplateObject: { id: number; the_file: string } = await axios.get(templateUrl).then((res) => { + return res.data; + }); // log the request const document_template_id = documentTemplateObject.id; @@ -112,28 +95,28 @@ export class ReportService { '{"myFormatter":"_function_myFormatter|function(data) { return data.slice(1); }","myOtherFormatter":"_function_myOtherFormatter|function(data) {return data.slice(2);}"}', options: { cacheReport: false, - convertTo: "docx", + convertTo: 'docx', overwrite: true, - reportName: "ticdi-report", + reportName: 'ticdi-report', }, template: { content: `${bufferBase64}`, - encodingType: "base64", - fileType: "docx", + encodingType: 'base64', + fileType: 'docx', }, }); const conf = { - method: "post", + method: 'post', url: process.env.cdogs_url, headers: { Authorization: `Bearer ${cdogsToken}`, - "Content-Type": "application/json", + 'Content-Type': 'application/json', }, - responseType: "arraybuffer", + responseType: 'arraybuffer', data: md, }; - const ax = require("axios"); + const ax = require('axios'); const response = await ax(conf).catch((error) => { console.log(error.response); }); @@ -163,20 +146,17 @@ export class ReportService { }); // get the document template - const documentTemplateObject: { id: number; the_file: string } = await axios - .get(templateUrl) - .then((res) => { - return res.data; - }); + const documentTemplateObject: { id: number; the_file: string } = await axios.get(templateUrl).then((res) => { + return res.data; + }); const interestParcel = rawData.interestParcel; const tenantAddr = rawData.tenantAddr; - const regVars = - { - regOfficeStreet: rawData && rawData.regOfficeStreet ? rawData.regOfficeStreet : '', - regOfficeCity: rawData && rawData.regOfficeCity ? rawData.regOfficeCity : '', - regOfficeProv: rawData && rawData.regOfficeProv ? rawData.regOfficeProv : '', - regOfficePostalCode: rawData && rawData.regOfficePostalCode ? rawData.regOfficePostalCode : '' - } + const regVars = { + regOfficeStreet: rawData && rawData.regOfficeStreet ? rawData.regOfficeStreet : '', + regOfficeCity: rawData && rawData.regOfficeCity ? rawData.regOfficeCity : '', + regOfficeProv: rawData && rawData.regOfficeProv ? rawData.regOfficeProv : '', + regOfficePostalCode: rawData && rawData.regOfficePostalCode ? rawData.regOfficePostalCode : '', + }; const glVariables = grazingLeaseVariables(tenantAddr, interestParcel, regVars); const data = { @@ -210,28 +190,28 @@ export class ReportService { '{"myFormatter":"_function_myFormatter|function(data) { return data.slice(1); }","myOtherFormatter":"_function_myOtherFormatter|function(data) {return data.slice(2);}"}', options: { cacheReport: false, - convertTo: "docx", + convertTo: 'docx', overwrite: true, - reportName: "ticdi-report", + reportName: 'ticdi-report', }, template: { content: `${bufferBase64}`, - encodingType: "base64", - fileType: "docx", + encodingType: 'base64', + fileType: 'docx', }, }); const conf = { - method: "post", + method: 'post', url: process.env.cdogs_url, headers: { Authorization: `Bearer ${cdogsToken}`, - "Content-Type": "application/json", + 'Content-Type': 'application/json', }, - responseType: "arraybuffer", + responseType: 'arraybuffer', data: md, }; - const ax = require("axios"); + const ax = require('axios'); const response = await ax(conf).catch((error) => { console.log(error.response); }); @@ -252,13 +232,13 @@ export class ReportService { const version = await axios .get(url, { headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json', }, }) .then((res) => { return res.data; }); - return { reportName: "NFR_" + tenureFileNumber + "_" + version }; + return { reportName: 'NFR_' + tenureFileNumber + '_' + version }; } async generateNFRReport( @@ -295,30 +275,24 @@ export class ReportService { const variables: any = {}; variableJson.forEach(({ variable_name, variable_value }) => { const newVariableName = variable_name - .replace(/_/g, " ") + .replace(/_/g, ' ') .toLowerCase() .replace(/\b\w/g, (match) => match.toUpperCase()) - .replace(/\s/g, "_") + .replace(/\s/g, '_') .replace(/^(\w)/, (match) => match.toUpperCase()); - if (variable_value.includes("«")) { + if (variable_value.includes('«')) { // regex which converts «DB_TENURE_TYPE» to {d.DB_Tenure_Type}, also works for VAR_ - variable_value = variable_value.replace( - /<<([^>>]+)>>/g, - function (match, innerText) { - innerText = convertToSpecialCamelCase(innerText); - return "{d." + innerText + "}"; - } - ); - } else if (variable_value.includes("<<")) { + variable_value = variable_value.replace(/<<([^>>]+)>>/g, function (match, innerText) { + innerText = convertToSpecialCamelCase(innerText); + return '{d.' + innerText + '}'; + }); + } else if (variable_value.includes('<<')) { // regex which converts <> to {d.DB_Tenure_Type}, also works for VAR_ - variable_value = variable_value.replace( - /<<([^>>]+)>>/g, - function (match, innerText) { - innerText = convertToSpecialCamelCase(innerText); - return "{d." + innerText + "}"; - } - ); + variable_value = variable_value.replace(/<<([^>>]+)>>/g, function (match, innerText) { + innerText = convertToSpecialCamelCase(innerText); + return '{d.' + innerText + '}'; + }); } variables[`VAR_${newVariableName}`] = variable_value; @@ -335,30 +309,23 @@ export class ReportService { const groupText = numberWords[group]; const varName = `Section${groupText}_${index}_Text`; - if (provision.free_text.includes("«")) { + if (provision.free_text.includes('«')) { // regex which converts «DB_TENURE_TYPE» to {d.DB_Tenure_Type}, also works for VAR_ - provision.free_text = provision.free_text.replace( - /«([^»]+)»/g, - function (match, innerText) { - innerText = convertToSpecialCamelCase(innerText); - return "{d." + innerText + "}"; - } - ); - } else if (provision.free_text.includes("<<")) { + provision.free_text = provision.free_text.replace(/«([^»]+)»/g, function (match, innerText) { + innerText = convertToSpecialCamelCase(innerText); + return '{d.' + innerText + '}'; + }); + } else if (provision.free_text.includes('<<')) { // regex which converts <> to {d.DB_Tenure_Type}, also works for VAR_ - provision.free_text = provision.free_text.replace( - /<<([^>>]+)>>/g, - function (match, innerText) { - innerText = convertToSpecialCamelCase(innerText); - return "{d." + innerText + "}"; - } - ); + provision.free_text = provision.free_text.replace(/<<([^>>]+)>>/g, function (match, innerText) { + innerText = convertToSpecialCamelCase(innerText); + return '{d.' + innerText + '}'; + }); } showProvisionSections[varName] = provision.free_text; // workaround for template formatting - if (showProvisionSections[varName] != "") { - showProvisionSections[varName] = - showProvisionSections[varName] + "\r\n\r\n"; + if (showProvisionSections[varName] != '') { + showProvisionSections[varName] = showProvisionSections[varName] + '\r\n\r\n'; } const showVarName = `showSection${groupText}_${index}`; @@ -367,13 +334,9 @@ export class ReportService { // Logic for including section titles based on which sections are displaying information for (const key in showProvisionSections) { - if (key.startsWith("showSection")) { + if (key.startsWith('showSection')) { const number = key.match(/Section(\w+)_\d+/)[1]; - if ( - number === "Twenty" || - number === "TwentyFive" || - number === "TwentySeven" - ) { + if (number === 'Twenty' || number === 'TwentyFive' || number === 'TwentySeven') { const titleKey = `Section${number}_Title`; // titleKey = Section_Title showProvisionSections[key] = showProvisionSections[key]; // key = showSection_<#> showProvisionSections[titleKey] = sectionTitles[number]; // set title text @@ -384,11 +347,17 @@ export class ReportService { // Format the raw ttls data const tenantAddr = rawData.tenantAddr; - const interestParcel = rawData.interestParcel[0]; + const interestParcels = rawData.interestParcel; + let concatLegalDescriptions = ''; + if (interestParcels && interestParcels.length > 0) { + let legalDescArray = []; + for (let ip of interestParcels) { + legalDescArray.push(ip.legalDescription); + } + concatLegalDescriptions = legalDescArray.join('\n'); + } - const DB_Address_Mailing_Tenant = tenantAddr[0] - ? nfrAddressBuilder(tenantAddr) - : ""; + const DB_Address_Mailing_Tenant = tenantAddr[0] ? nfrAddressBuilder(tenantAddr) : ''; const VAR_Fee_Documentation_Amount: number = variables && variables.VAR_Fee_Documentation_Amount @@ -398,10 +367,8 @@ export class ReportService { : 0; if (variables && variables.VAR_Fee_Documentation_Amount) { !isNaN(variables.VAR_Fee_Documentation_Amount) - ? (variables.VAR_Fee_Documentation_Amount = formatMoney( - parseFloat(variables.VAR_Fee_Documentation_Amount) - )) - : (variables.VAR_Fee_Documentation_Amount = "0.00"); + ? (variables.VAR_Fee_Documentation_Amount = formatMoney(parseFloat(variables.VAR_Fee_Documentation_Amount))) + : (variables.VAR_Fee_Documentation_Amount = '0.00'); } const VAR_Fee_Application_Amount: number = @@ -412,10 +379,8 @@ export class ReportService { : 0; if (variables && variables.VAR_Fee_Application_Amount) { !isNaN(variables.VAR_Fee_Application_Amount) - ? (variables.VAR_Fee_Application_Amount = formatMoney( - parseFloat(variables.VAR_Fee_Application_Amount) - )) - : (variables.VAR_Fee_Application_Amount = "0.00"); + ? (variables.VAR_Fee_Application_Amount = formatMoney(parseFloat(variables.VAR_Fee_Application_Amount))) + : (variables.VAR_Fee_Application_Amount = '0.00'); } const VAR_Fee_Occupational_Rental_Amount: number = @@ -433,7 +398,7 @@ export class ReportService { parseFloat(variables.VAR_Fee_Occupational_Rental_Amount) ); } else { - variables.VAR_Fee_Occupational_Rental_Amount = "0.00"; + variables.VAR_Fee_Occupational_Rental_Amount = '0.00'; } } @@ -445,26 +410,18 @@ export class ReportService { : 0; if (variables && variables.VAR_Fee_Other_Credit_Amount) { !isNaN(variables.VAR_Fee_Other_Credit_Amount) - ? (variables.VAR_Fee_Other_Credit_Amount = formatMoney( - parseFloat(variables.VAR_Fee_Other_Credit_Amount) - )) - : (variables.VAR_Fee_Other_Credit_Amount = "0.00"); + ? (variables.VAR_Fee_Other_Credit_Amount = formatMoney(parseFloat(variables.VAR_Fee_Other_Credit_Amount))) + : (variables.VAR_Fee_Other_Credit_Amount = '0.00'); } const GST_Rate: number = rawData && rawData.gstRate ? rawData.gstRate : 0; const DB_Fee_Payable_Type: string = rawData.feePayableType; - const DB_Fee_Payable_Amount: number = rawData.feePayableAmount - ? rawData.feePayableAmount - : 0; - const DB_Fee_Payable_Amount_GST: number = rawData.feePayableAmountGst - ? rawData.feePayableAmountGst - : 0; - const DB_GST_Exempt: string = rawData.gstExempt ? rawData.gstExempt : "N"; - const DB_GST_Exempt_Area: number = rawData.gstExemptArea - ? rawData.gstExemptArea - : 0; + const DB_Fee_Payable_Amount: number = rawData.feePayableAmount ? rawData.feePayableAmount : 0; + const DB_Fee_Payable_Amount_GST: number = rawData.feePayableAmountGst ? rawData.feePayableAmountGst : 0; + const DB_GST_Exempt: string = rawData.gstExempt ? rawData.gstExempt : 'N'; + const DB_GST_Exempt_Area: number = rawData.gstExemptArea ? rawData.gstExemptArea : 0; let DB_Total_GST_Amount: number; - const DB_FP_Asterisk: string = DB_GST_Exempt === "Y" ? "" : "*"; + const DB_FP_Asterisk: string = DB_GST_Exempt === 'Y' ? '' : '*'; let totalArea = 0; if (rawData.interestParcel && rawData.interestParcel[0]) { @@ -477,11 +434,9 @@ export class ReportService { // Get the ratio of the taxable are to the totalArea const areaRatio = totalArea !== 0 ? taxableArea / totalArea : 0; - if (DB_GST_Exempt === "Y") { + if (DB_GST_Exempt === 'Y') { DB_Total_GST_Amount = - ((DB_Fee_Payable_Amount_GST * areaRatio + - VAR_Fee_Documentation_Amount + - VAR_Fee_Application_Amount) * + ((DB_Fee_Payable_Amount_GST * areaRatio + VAR_Fee_Documentation_Amount + VAR_Fee_Application_Amount) * GST_Rate) / 100.0; } else { @@ -504,87 +459,66 @@ export class ReportService { VAR_Fee_Other_Credit_Amount; let monies = []; - const Show_Fee_Payable_Amount_GST = DB_Fee_Payable_Amount_GST - ? DB_Fee_Payable_Amount_GST > 0 - ? 1 - : 0 - : 0; + const Show_Fee_Payable_Amount_GST = DB_Fee_Payable_Amount_GST ? (DB_Fee_Payable_Amount_GST > 0 ? 1 : 0) : 0; if (Show_Fee_Payable_Amount_GST === 1) { monies.push({ description: DB_Fee_Payable_Type, - dollarSign: "*$", + dollarSign: '*$', value: formatMoney(DB_Fee_Payable_Amount_GST), }); } - const Show_Fee_Payable_Amount = DB_Fee_Payable_Amount - ? DB_Fee_Payable_Amount > 0 - ? 1 - : 0 - : 0; + const Show_Fee_Payable_Amount = DB_Fee_Payable_Amount ? (DB_Fee_Payable_Amount > 0 ? 1 : 0) : 0; if (Show_Fee_Payable_Amount === 1) { monies.push({ description: DB_Fee_Payable_Type, - dollarSign: "$", + dollarSign: '$', value: formatMoney(DB_Fee_Payable_Amount), }); } - const Show_Fee_Occupational_Rental_Amount = - VAR_Fee_Occupational_Rental_Amount - ? VAR_Fee_Occupational_Rental_Amount > 0 - ? 1 - : 0 - : 0; + const Show_Fee_Occupational_Rental_Amount = VAR_Fee_Occupational_Rental_Amount + ? VAR_Fee_Occupational_Rental_Amount > 0 + ? 1 + : 0 + : 0; if (Show_Fee_Occupational_Rental_Amount === 1) { monies.push({ - description: "Occupational Rental Amount", + description: 'Occupational Rental Amount', dollarSign: `${DB_FP_Asterisk}$`, value: formatMoney(VAR_Fee_Occupational_Rental_Amount), }); } - const Show_Fee_Documentation_Amount = VAR_Fee_Documentation_Amount - ? VAR_Fee_Documentation_Amount > 0 - ? 1 - : 0 - : 0; + const Show_Fee_Documentation_Amount = VAR_Fee_Documentation_Amount ? (VAR_Fee_Documentation_Amount > 0 ? 1 : 0) : 0; if (Show_Fee_Documentation_Amount === 1) { monies.push({ - description: "Documentation Amount", - dollarSign: "*$", + description: 'Documentation Amount', + dollarSign: '*$', value: formatMoney(VAR_Fee_Documentation_Amount), }); } - const Show_Fee_Application_Amount = VAR_Fee_Application_Amount - ? VAR_Fee_Application_Amount > 0 - ? 1 - : 0 - : 0; + const Show_Fee_Application_Amount = VAR_Fee_Application_Amount ? (VAR_Fee_Application_Amount > 0 ? 1 : 0) : 0; if (Show_Fee_Application_Amount === 1) { monies.push({ - description: "Application Amount", - dollarSign: "*$", + description: 'Application Amount', + dollarSign: '*$', value: formatMoney(VAR_Fee_Application_Amount), }); } - const Show_Fee_Other_Credit_Amount = VAR_Fee_Other_Credit_Amount - ? VAR_Fee_Other_Credit_Amount > 0 - ? 1 - : 0 - : 0; + const Show_Fee_Other_Credit_Amount = VAR_Fee_Other_Credit_Amount ? (VAR_Fee_Other_Credit_Amount > 0 ? 1 : 0) : 0; if (Show_Fee_Other_Credit_Amount === 1) { monies.push({ - description: "Other (credit)", - dollarSign: "$", + description: 'Other (credit)', + dollarSign: '$', value: formatMoney(VAR_Fee_Other_Credit_Amount), }); } monies.push({ - description: "GST Total", - dollarSign: "$", + description: 'GST Total', + dollarSign: '$', value: formatMoney(DB_Total_GST_Amount), }); const moniesTotal = { - description: "Total Fees Payable", - dollarSign: "$", + description: 'Total Fees Payable', + dollarSign: '$', value: formatMoney(DB_Total_Monies_Payable), }; @@ -603,17 +537,11 @@ export class ReportService { DB_File_Number: rawData.fileNum, DB_Address_Mailing_Tenant: DB_Address_Mailing_Tenant, DB_Tenure_Type: rawData.type // convert a tenure type like LICENSE to License - ? rawData.type.toLowerCase().charAt(0).toUpperCase() + - rawData.type.toLowerCase().slice(1) - : "", - DB_Legal_Description: interestParcel - ? interestParcel.legalDescription - : "", + ? rawData.type.toLowerCase().charAt(0).toUpperCase() + rawData.type.toLowerCase().slice(1) + : '', + DB_Legal_Description: concatLegalDescriptions, DB_Fee_Payable_Type: DB_Fee_Payable_Type, - DB_Fee_Payable_Amount_GST: - DB_Fee_Payable_Amount_GST == 0 - ? "" - : formatMoney(DB_Fee_Payable_Amount_GST), + DB_Fee_Payable_Amount_GST: DB_Fee_Payable_Amount_GST == 0 ? '' : formatMoney(DB_Fee_Payable_Amount_GST), DB_Fee_Payable_Amount: formatMoney(DB_Fee_Payable_Amount), DB_FP_Asterisk: DB_FP_Asterisk, DB_Total_GST_Amount: formatMoney(DB_Total_GST_Amount), @@ -641,14 +569,7 @@ export class ReportService { }); // Save the NFR Data - await this.saveNFR( - dtid, - variantName, - "Complete", - provisionJson, - variableJson, - idirUsername - ); + await this.saveNFR(dtid, variantName, 'Complete', provisionJson, variableJson, idirUsername); // Generate the report const cdogsToken = await this.ttlsService.callGetToken(); @@ -659,36 +580,36 @@ export class ReportService { '{"myFormatter":"_function_myFormatter|function(data) { return data.slice(1); }","myOtherFormatter":"_function_myOtherFormatter|function(data) {return data.slice(2);}"}', options: { cacheReport: false, - convertTo: "docx", + convertTo: 'docx', overwrite: true, - reportName: "nfr-report", + reportName: 'nfr-report', }, template: { content: `${bufferBase64}`, - encodingType: "base64", - fileType: "docx", + encodingType: 'base64', + fileType: 'docx', }, }; const md = JSON.stringify(cdogsData); let conf = { - method: "post", + method: 'post', url: process.env.cdogs_url, headers: { Authorization: `Bearer ${cdogsToken}`, - "Content-Type": "application/json", + 'Content-Type': 'application/json', }, - responseType: "arraybuffer", + responseType: 'arraybuffer', data: md, }; - const ax = require("axios"); + const ax = require('axios'); const response = await ax(conf).catch((error) => { console.log(error.response); }); // response.data is the docx file after the first insertions const firstFile = response.data; // convert the docx file buffer to base64 for a second cdogs conversion - const base64File = Buffer.from(firstFile).toString("base64"); + const base64File = Buffer.from(firstFile).toString('base64'); cdogsData.template.content = base64File; const md2 = JSON.stringify(cdogsData); conf.data = md2; @@ -700,19 +621,16 @@ export class ReportService { return response2.data; } - async getNFRProvisionsByVariantAndDtid( - variantName: string, - dtid: number - ): Promise { + async getNFRProvisionsByVariantAndDtid(variantName: string, dtid: number): Promise { const returnItems = [ - "type", - "provision_name", - "help_text", - "free_text", - "category", - "provision_group", - "id", - "mandatory", + 'type', + 'provision_name', + 'help_text', + 'free_text', + 'category', + 'provision_group', + 'id', + 'mandatory', ]; let reduced, provisions; // nfrDataId exists so return a list of provisions with pre-existing free_text data inserted, certain provisions preselected @@ -758,9 +676,9 @@ export class ReportService { // make the returned data readable for the ajax request return reduced.map((obj) => { const groupObj = obj.provision_group; - delete obj["provision_group"]; - obj["max"] = groupObj.max; - obj["provision_group"] = groupObj.provision_group; + delete obj['provision_group']; + obj['max'] = groupObj.max; + obj['provision_group'] = groupObj.provision_group; return obj; }); } @@ -772,10 +690,7 @@ export class ReportService { }); } - async getNFRVariablesByVariantAndDtid( - variantName: string, - dtid: number - ): Promise { + async getNFRVariablesByVariantAndDtid(variantName: string, dtid: number): Promise { // if an nfrId is provided, get the variables with any existing user specified values const url = `${hostname}:${port}/nfr-data/variables/${variantName}/${dtid}`; const variables = await axios @@ -851,7 +766,7 @@ export class ReportService { dtid: nfr.dtid, version: template.template_version, file_name: template.file_name, - updated_date: nfr.update_timestamp.split("T")[0], + updated_date: nfr.update_timestamp.split('T')[0], status: nfr.status, active: template.active_flag, nfr_id: nfr.id, @@ -873,7 +788,7 @@ export class ReportService { return axios .get(url, { headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json', }, }) .then((res) => { @@ -920,10 +835,7 @@ export class ReportService { }); } - async getEnabledProvisionsByVariantAndDtid( - variantName: string, - dtid: number - ) { + async getEnabledProvisionsByVariantAndDtid(variantName: string, dtid: number) { const url = `${hostname}:${port}/nfr-data/get-enabled-provisions/${variantName}/${dtid}`; return axios.get(url).then((res) => { return res.data; From b85cd7bcc71e03c694fbd324f60ef2bb71cc777f Mon Sep 17 00:00:00 2001 From: mgtennant <100305096+mgtennant@users.noreply.github.com> Date: Tue, 23 Jan 2024 16:04:39 -0800 Subject: [PATCH 2/9] update to fix & import fix --- frontend/src/admin/admin.service.ts | 234 +++++++++++--------------- frontend/src/report/report.service.ts | 14 +- 2 files changed, 103 insertions(+), 145 deletions(-) diff --git a/frontend/src/admin/admin.service.ts b/frontend/src/admin/admin.service.ts index 4e414baa..fd6fcbb2 100644 --- a/frontend/src/admin/admin.service.ts +++ b/frontend/src/admin/admin.service.ts @@ -1,10 +1,10 @@ -import { Injectable } from "@nestjs/common"; -import * as dotenv from "dotenv"; -import { HttpService } from "@nestjs/axios"; -import { ExportDataObject, SearchResultsItem, UserObject } from "utils/types"; -import { REPORT_TYPES } from "utils/constants"; -const axios = require("axios"); -const FormData = require("form-data"); +import { Injectable } from '@nestjs/common'; +import * as dotenv from 'dotenv'; +import { HttpService } from '@nestjs/axios'; +import { ExportDataObject, SearchResultsItem, UserObject } from '../../utils/types'; +import { REPORT_TYPES } from '../../utils/constants'; +const axios = require('axios'); +const FormData = require('form-data'); dotenv.config(); let hostname: string; @@ -13,18 +13,12 @@ let port: number; @Injectable() export class AdminService { constructor(private readonly httpService: HttpService) { - hostname = process.env.backend_url - ? process.env.backend_url - : `http://localhost`; + hostname = process.env.backend_url ? process.env.backend_url : `http://localhost`; // local development backend port is 3001, docker backend port is 3000 port = process.env.backend_url ? 3000 : 3001; } - async activateTemplate(data: { - id: number; - update_userid: string; - document_type: string; - }): Promise { + async activateTemplate(data: { id: number; update_userid: string; document_type: string }): Promise { const url = `${hostname}:${port}/document-template/activate-template`; return axios .post(url, { @@ -45,9 +39,7 @@ export class AdminService { } async removeTemplate(reportType: string, id: number): Promise { - const url = `${hostname}:${port}/document-template/remove/${encodeURI( - reportType - )}/${id}`; + const url = `${hostname}:${port}/document-template/remove/${encodeURI(reportType)}/${id}`; return axios.get(url).then((res) => { return res.data; }); @@ -66,13 +58,13 @@ export class AdminService { ): Promise { const url = `${hostname}:${port}/document-template/create`; const form: any = new FormData(); - form.append("document_type", data.document_type); - form.append("active_flag", data.active_flag); - form.append("mime_type", data.mime_type); - form.append("file_name", data.file_name); - form.append("template_author", data.template_author); - form.append("create_userid", data.create_userid); - form.append("file", file.buffer, "file"); + form.append('document_type', data.document_type); + form.append('active_flag', data.active_flag); + form.append('mime_type', data.mime_type); + form.append('file_name', data.file_name); + form.append('template_author', data.template_author); + form.append('create_userid', data.create_userid); + form.append('file', file.buffer, 'file'); return axios.post(url, form).then((res) => { return res.data; }); @@ -81,15 +73,15 @@ export class AdminService { async getToken() { const url = process.env.users_api_token_url; const token = `${process.env.users_api_client_id}:${process.env.users_api_client_secret}`; - const encodedToken = Buffer.from(token).toString("base64"); + const encodedToken = Buffer.from(token).toString('base64'); const config = { headers: { - "Content-Type": "application/x-www-form-urlencoded", - Authorization: "Basic " + encodedToken, + 'Content-Type': 'application/x-www-form-urlencoded', + Authorization: 'Basic ' + encodedToken, }, }; const grantTypeParam = new URLSearchParams(); - grantTypeParam.append("grant_type", "client_credentials"); + grantTypeParam.append('grant_type', 'client_credentials'); return axios .post(url, grantTypeParam, config) .then((response) => { @@ -118,27 +110,27 @@ export class AdminService { const bearerToken = await this.getToken(); const searchData: SearchResultsItem[] = await axios .get(url, { - headers: { Authorization: "Bearer " + bearerToken }, + headers: { Authorization: 'Bearer ' + bearerToken }, }) .then((res) => { return res.data.data; }) .catch((err) => { console.log(err.response.data); - throw new Error("No users found"); + throw new Error('No users found'); }); - const firstName = searchData[0].firstName ? searchData[0].firstName : ""; - const lastName = searchData[0].lastName ? searchData[0].lastName : ""; + const firstName = searchData[0].firstName ? searchData[0].firstName : ''; + const lastName = searchData[0].lastName ? searchData[0].lastName : ''; const username = searchData[0].attributes ? searchData[0].attributes.idir_username[0] ? searchData[0].attributes.idir_username[0] - : "" - : ""; + : '' + : ''; const idirUsername = searchData[0].attributes ? searchData[0].attributes.idir_user_guid[0] ? searchData[0].attributes.idir_user_guid[0] - : "" - : ""; + : '' + : ''; const userObject = { firstName: firstName, lastName: lastName, @@ -148,7 +140,7 @@ export class AdminService { const roleUrl = `${process.env.users_api_base_url}/integrations/${process.env.integration_id}/${process.env.css_environment}/users/${idirUsername}@idir/roles`; const roles = await axios .get(roleUrl, { - headers: { Authorization: "Bearer " + bearerToken }, + headers: { Authorization: 'Bearer ' + bearerToken }, }) .then((res) => { return res.data; @@ -159,12 +151,12 @@ export class AdminService { }); let isAdmin: boolean = false; for (let entry of roles.data) { - if (entry && entry.name == "ticdi_admin") { + if (entry && entry.name == 'ticdi_admin') { isAdmin = true; } } if (isAdmin) { - throw new Error("That user is already a TICDI admin"); + throw new Error('That user is already a TICDI admin'); } return userObject; } @@ -184,34 +176,34 @@ export class AdminService { const bearerToken = await this.getToken(); const searchData: SearchResultsItem[] = await axios .get(url, { - headers: { Authorization: "Bearer " + bearerToken }, + headers: { Authorization: 'Bearer ' + bearerToken }, }) .then((res) => { return res.data.data; }) .catch((err) => console.log(err.response.data)); if (searchData.length > 1) { - throw new Error("More than one user was found"); + throw new Error('More than one user was found'); } else if (searchData.length == 0) { - throw new Error("No users were found"); + throw new Error('No users were found'); } const userObject: UserObject = this.formatSearchData(searchData)[0]; await axios .post( addAdminUrl, { - roleName: "ticdi_admin", - username: userObject.idirUsername + "@idir", - operation: "add", + roleName: 'ticdi_admin', + username: userObject.idirUsername + '@idir', + operation: 'add', }, - { headers: { Authorization: "Bearer " + bearerToken } } + { headers: { Authorization: 'Bearer ' + bearerToken } } ) .then((res) => { return res.data; }) .catch((err) => { console.log(err); - throw new Error("Failed to add admin role"); + throw new Error('Failed to add admin role'); }); return userObject; } @@ -226,7 +218,7 @@ export class AdminService { const url = `${process.env.users_api_base_url}/integrations/${process.env.integration_id}/${process.env.css_environment}/roles/ticdi_admin/users`; const data: SearchResultsItem[] = await axios .get(url, { - headers: { Authorization: "Bearer " + bearerToken }, + headers: { Authorization: 'Bearer ' + bearerToken }, }) .then((res) => { return res.data.data; @@ -241,7 +233,7 @@ export class AdminService { const url = `${process.env.users_api_base_url}/integrations/${process.env.integration_id}/${process.env.css_environment}/roles/ticdi_admin/users`; const data: SearchResultsItem[] = await axios .get(url, { - headers: { Authorization: "Bearer " + bearerToken }, + headers: { Authorization: 'Bearer ' + bearerToken }, }) .then((res) => { return res.data.data; @@ -258,29 +250,26 @@ export class AdminService { * @returns null */ async removeAdmin(username: string) { - const ticdiAdminRole = "ticdi_admin"; + const ticdiAdminRole = 'ticdi_admin'; const bearerToken = await this.getToken(); const url = `${process.env.users_api_base_url}/integrations/${process.env.integration_id}/${process.env.css_environment}/users/${username}@idir/roles/${ticdiAdminRole}`; const res = await axios .delete(url, { - headers: { Authorization: "Bearer " + bearerToken }, + headers: { Authorization: 'Bearer ' + bearerToken }, }) .then((res) => { return res; }) .catch((err) => { console.log(err.response.data); - return { message: "Failed to remove admin privileges" }; + return { message: 'Failed to remove admin privileges' }; }); - return { message: "success" }; + return { message: 'success' }; } async getTemplates(reportId: number) { - const documentType = - reportId == 1 || reportId == 2 ? REPORT_TYPES[reportId - 1] : "none"; - const url = `${hostname}:${port}/document-template/${encodeURI( - documentType - )}`; + const documentType = reportId == 1 || reportId == 2 ? REPORT_TYPES[reportId - 1] : 'none'; + const url = `${hostname}:${port}/document-template/${encodeURI(documentType)}`; const data = await axios .get(url) .then((res) => { @@ -299,8 +288,8 @@ export class AdminService { const document = { version: entry.template_version, file_name: entry.file_name, - updated_date: entry.update_timestamp.split("T")[0], - status: "???", + updated_date: entry.update_timestamp.split('T')[0], + status: '???', active: entry.active_flag, template_id: entry.id, }; @@ -310,17 +299,8 @@ export class AdminService { } async getDocumentTemplates(documentType: string): Promise { - const returnItems = [ - "id", - "template_version", - "file_name", - "uploaded_date", - "active_flag", - "update_timestamp", - ]; - const url = `${hostname}:${port}/document-template/${encodeURI( - documentType - )}`; + const returnItems = ['id', 'template_version', 'file_name', 'uploaded_date', 'active_flag', 'update_timestamp']; + const url = `${hostname}:${port}/document-template/${encodeURI(documentType)}`; const documentTemplateObjects = await axios .get(url) .then((res) => { @@ -332,29 +312,27 @@ export class AdminService { .filter((key) => returnItems.includes(key)) .reduce( (acc, key) => { - key == "update_timestamp" - ? (acc[key] = obj[key].split("T")[0]) - : (acc[key] = obj[key]); + key == 'update_timestamp' ? (acc[key] = obj[key].split('T')[0]) : (acc[key] = obj[key]); return acc; }, - { view: "view", remove: "remove" } + { view: 'view', remove: 'remove' } ) ); } async getNFRProvisions(): Promise { const returnItems = [ - "id", - "dtid", - "type", - "provision_group", - "max", - "provision_name", - "free_text", - "help_text", - "category", - "active_flag", - "variants", + 'id', + 'dtid', + 'type', + 'provision_group', + 'max', + 'provision_name', + 'free_text', + 'help_text', + 'category', + 'active_flag', + 'variants', ]; const url = `${hostname}:${port}/nfr-provision`; const nfrProvisions = await axios @@ -371,19 +349,13 @@ export class AdminService { acc[key] = obj[key]; return acc; }, - { edit: "edit" } + { edit: 'edit' } ) ); } async getNFRVariables(): Promise { - const returnItems = [ - "variable_name", - "variable_value", - "help_text", - "id", - "provision_id", - ]; + const returnItems = ['variable_name', 'variable_value', 'help_text', 'id', 'provision_id']; const url = `${hostname}:${port}/nfr-provision/variables`; const nfrVariables = await axios .get(url) @@ -399,7 +371,7 @@ export class AdminService { acc[key] = obj[key]; return acc; }, - { edit: "edit", remove: "remove" } + { edit: 'edit', remove: 'remove' } ) ); } @@ -440,11 +412,9 @@ export class AdminService { create_userid: string ) { const url = `${hostname}:${port}/nfr-provision`; - return await axios - .post(url, { ...provisionParams, create_userid }) - .then((res) => { - return res.data; - }); + return await axios.post(url, { ...provisionParams, create_userid }).then((res) => { + return res.data; + }); } async updateProvision( @@ -463,11 +433,9 @@ export class AdminService { update_userid: string ) { const url = `${hostname}:${port}/nfr-provision/update`; - return await axios - .post(url, { ...provisionParams, update_userid }) - .then((res) => { - return res.data; - }); + return await axios.post(url, { ...provisionParams, update_userid }).then((res) => { + return res.data; + }); } async addVariable( @@ -480,11 +448,9 @@ export class AdminService { create_userid: string ) { const url = `${hostname}:${port}/nfr-provision/add-variable`; - return await axios - .post(url, { ...variableParams, create_userid }) - .then((res) => { - return res.data; - }); + return await axios.post(url, { ...variableParams, create_userid }).then((res) => { + return res.data; + }); } async updateVariable( @@ -497,11 +463,9 @@ export class AdminService { update_userid: string ) { const url = `${hostname}:${port}/nfr-provision/update-variable`; - return await axios - .post(url, { ...variableParams, update_userid }) - .then((res) => { - return res.data; - }); + return await axios.post(url, { ...variableParams, update_userid }).then((res) => { + return res.data; + }); } async removeVariable(id: number) { @@ -518,20 +482,16 @@ export class AdminService { formatSearchData(data: SearchResultsItem[]): UserObject[] { let userObjectArray = []; for (let entry of data) { - const firstName = entry.firstName ? entry.firstName : ""; - const lastName = entry.lastName ? entry.lastName : ""; - const username = entry.attributes.idir_username[0] - ? entry.attributes.idir_username[0] - : ""; - const email = entry.email ? entry.email : ""; - const idirUsername = entry.username - ? entry.username.replace("@idir", "") - : ""; + const firstName = entry.firstName ? entry.firstName : ''; + const lastName = entry.lastName ? entry.lastName : ''; + const username = entry.attributes.idir_username[0] ? entry.attributes.idir_username[0] : ''; + const email = entry.email ? entry.email : ''; + const idirUsername = entry.username ? entry.username.replace('@idir', '') : ''; const userObject: UserObject = { - name: firstName + " " + lastName, + name: firstName + ' ' + lastName, username: username, email: email, - remove: "Remove", + remove: 'Remove', idirUsername: idirUsername, }; userObjectArray.push(userObject); @@ -547,19 +507,13 @@ export class AdminService { formatExportData(data: SearchResultsItem[]): ExportDataObject[] { let exportDataObjectArray = []; for (let entry of data) { - let firstName = entry.firstName ? entry.firstName : ""; - let lastName = entry.lastName ? entry.lastName : ""; - let username = entry.username ? entry.username : ""; - let email = entry.email ? entry.email : ""; - let idir_user_guid = entry.attributes.idir_user_guid[0] - ? entry.attributes.idir_user_guid[0] - : ""; - let idir_username = entry.attributes.idir_username[0] - ? entry.attributes.idir_username[0] - : ""; - let display_name = entry.attributes.display_name[0] - ? entry.attributes.display_name[0] - : ""; + let firstName = entry.firstName ? entry.firstName : ''; + let lastName = entry.lastName ? entry.lastName : ''; + let username = entry.username ? entry.username : ''; + let email = entry.email ? entry.email : ''; + let idir_user_guid = entry.attributes.idir_user_guid[0] ? entry.attributes.idir_user_guid[0] : ''; + let idir_username = entry.attributes.idir_username[0] ? entry.attributes.idir_username[0] : ''; + let display_name = entry.attributes.display_name[0] ? entry.attributes.display_name[0] : ''; const exportDataObject: ExportDataObject = { firstName: '"' + firstName + '"', lastName: '"' + lastName + '"', diff --git a/frontend/src/report/report.service.ts b/frontend/src/report/report.service.ts index f5a23137..d153e365 100644 --- a/frontend/src/report/report.service.ts +++ b/frontend/src/report/report.service.ts @@ -2,9 +2,9 @@ import { Injectable } from '@nestjs/common'; import * as dotenv from 'dotenv'; import { firstValueFrom } from 'rxjs'; import { TTLSService } from 'src/ttls/ttls.service'; -import { GL_REPORT_TYPE, LUR_REPORT_TYPE, numberWords, sectionTitles } from 'utils/constants'; -import { ProvisionJSON, VariableJSON } from 'utils/types'; -import { convertToSpecialCamelCase, formatMoney, grazingLeaseVariables, nfrAddressBuilder } from 'utils/util'; +import { GL_REPORT_TYPE, LUR_REPORT_TYPE, numberWords, sectionTitles } from '../../utils/constants'; +import { ProvisionJSON, VariableJSON } from '../../utils/types'; +import { convertToSpecialCamelCase, formatMoney, grazingLeaseVariables, nfrAddressBuilder } from '../../utils/util'; const axios = require('axios'); dotenv.config(); @@ -352,9 +352,13 @@ export class ReportService { if (interestParcels && interestParcels.length > 0) { let legalDescArray = []; for (let ip of interestParcels) { - legalDescArray.push(ip.legalDescription); + if (ip.legalDescription && ip.legalDescription != '') { + legalDescArray.push(ip.legalDescription); + } + } + if (legalDescArray.length > 0) { + concatLegalDescriptions = legalDescArray.join('\n'); } - concatLegalDescriptions = legalDescArray.join('\n'); } const DB_Address_Mailing_Tenant = tenantAddr[0] ? nfrAddressBuilder(tenantAddr) : ''; From 7f786fc87176b781d5b48fb6179501e7d9fc5815 Mon Sep 17 00:00:00 2001 From: mgtennant <100305096+mgtennant@users.noreply.github.com> Date: Tue, 23 Jan 2024 16:05:02 -0800 Subject: [PATCH 3/9] import fix --- frontend/src/app.controller.ts | 334 +++++++++++---------------------- 1 file changed, 114 insertions(+), 220 deletions(-) diff --git a/frontend/src/app.controller.ts b/frontend/src/app.controller.ts index 4cf34cf2..40aaf80e 100644 --- a/frontend/src/app.controller.ts +++ b/frontend/src/app.controller.ts @@ -1,33 +1,17 @@ -import { - Get, - Controller, - Render, - Param, - UseGuards, - UseFilters, - Session, - Query, - Res, -} from "@nestjs/common"; -import { AppService } from "./app.service"; -import { - NFR_VARIANTS, - NFR_VARIANTS_ARRAY, - PAGE_TITLES, - REPORT_TYPES, - REPORT_URLS, -} from "utils/constants"; -import { SessionData } from "utils/types"; -import { AuthenticationGuard } from "./authentication/authentication.guard"; -import { AuthenticationFilter } from "./authentication/authentication.filter"; -import { TTLSService } from "./ttls/ttls.service"; -import { AdminGuard } from "./admin/admin.guard"; -import { AxiosRequestConfig } from "axios"; -import { firstValueFrom } from "rxjs"; -import { Req } from "@nestjs/common/decorators/http/route-params.decorator"; -import { Request, Response } from "express"; -import { ReportService } from "./report/report.service"; -import { nfrInterestedParties } from "utils/util"; +import { Get, Controller, Render, Param, UseGuards, UseFilters, Session, Query, Res } from '@nestjs/common'; +import { AppService } from './app.service'; +import { NFR_VARIANTS, NFR_VARIANTS_ARRAY, PAGE_TITLES, REPORT_TYPES } from '../utils/constants'; +import { SessionData } from '../utils/types'; +import { AuthenticationGuard } from './authentication/authentication.guard'; +import { AuthenticationFilter } from './authentication/authentication.filter'; +import { TTLSService } from './ttls/ttls.service'; +import { AdminGuard } from './admin/admin.guard'; +import { AxiosRequestConfig } from 'axios'; +import { firstValueFrom } from 'rxjs'; +import { Req } from '@nestjs/common/decorators/http/route-params.decorator'; +import { Request, Response } from 'express'; +import { ReportService } from './report/report.service'; +import { nfrInterestedParties } from '../utils/util'; // let requestUrl: string; @@ -40,51 +24,40 @@ export class AppController { private readonly reportService: ReportService, private readonly ttlsService: TTLSService ) { - const hostname = process.env.backend_url - ? process.env.backend_url - : `http://localhost`; + const hostname = process.env.backend_url ? process.env.backend_url : `http://localhost`; const port = process.env.backend_url ? 3000 : 3001; requestUrl = `${hostname}:${port}/document-template/`; requestConfig = { headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json', }, }; } @Get() - @Render("index") + @Render('index') @UseFilters(AuthenticationFilter) @UseGuards(AuthenticationGuard) async root(@Session() session: { data?: SessionData }) { let isAdmin = false; - if ( - session.data && - session.data.activeAccount && - session.data.activeAccount.client_roles - ) { + if (session.data && session.data.activeAccount && session.data.activeAccount.client_roles) { for (let role of session.data.activeAccount.client_roles) { - if (role == "ticdi_admin") { + if (role == 'ticdi_admin') { isAdmin = true; } } } - const displayAdmin = isAdmin ? "Administration" : "-"; + const displayAdmin = isAdmin ? 'Administration' : '-'; const title = - process.env.ticdi_environment == "DEVELOPMENT" - ? "DEVELOPMENT - " + PAGE_TITLES.INDEX - : PAGE_TITLES.INDEX; + process.env.ticdi_environment == 'DEVELOPMENT' ? 'DEVELOPMENT - ' + PAGE_TITLES.INDEX : PAGE_TITLES.INDEX; return { title: title, - idirUsername: session.data.activeAccount - ? session.data.activeAccount.idir_username - : "", - primaryContactName: "", + idirUsername: session.data.activeAccount ? session.data.activeAccount.idir_username : '', + primaryContactName: '', displayAdmin: displayAdmin, }; } - /** * Renders the non-LUR report pages * @@ -93,23 +66,23 @@ export class AppController { * @param documentType * @returns */ - @Get("dtid/:dtid/:documentType") + @Get('dtid/:dtid/:documentType') @UseFilters(AuthenticationFilter) @UseGuards(AuthenticationGuard) async reportPage( @Session() session: { data?: SessionData }, - @Param("dtid") dtid: number, - @Param("documentType") documentType, + @Param('dtid') dtid: number, + @Param('documentType') documentType, @Req() req: Request, @Res() res: Response ) { - console.log('Report page document type: '+documentType); - let decodedDocumentType = decodeURIComponent(documentType) - decodedDocumentType = decodedDocumentType.toUpperCase().replace(/\s+/g, "").replace(/-/g, "").replace(/–/g,""); - console.log(decodedDocumentType) - if (decodedDocumentType == "GRAZINGLEASE" || decodedDocumentType == "AGRICULTURALLEASEUGRAZINGMP") { + console.log('Report page document type: ' + documentType); + let decodedDocumentType = decodeURIComponent(documentType); + decodedDocumentType = decodedDocumentType.toUpperCase().replace(/\s+/g, '').replace(/-/g, '').replace(/–/g, ''); + console.log(decodedDocumentType); + if (decodedDocumentType == 'GRAZINGLEASE' || decodedDocumentType == 'AGRICULTURALLEASEUGRAZINGMP') { return this.getGrazingLeaseDisplayData(session, dtid, res); - } else if (decodedDocumentType.includes("NOTICEOFFINALREVIEW")){ + } else if (decodedDocumentType.includes('NOTICEOFFINALREVIEW')) { return this.getNfrDisplayData(session, dtid, documentType, res); } else { return this.landUseReportPage(session, dtid, req, res); @@ -123,11 +96,12 @@ export class AppController { * @param id * @returns */ - @Get("dtid/:dtid") + @Get('dtid/:dtid') @UseFilters(AuthenticationFilter) @UseGuards(AuthenticationGuard) - async landUserReportRedirect(@Session() session: {data?:SessionData}, - @Param("dtid") dtid, + async landUserReportRedirect( + @Session() session: { data?: SessionData }, + @Param('dtid') dtid, @Req() req: Request, @Res() res: Response ) { @@ -138,116 +112,86 @@ export class AppController { @UseGuards(AuthenticationGuard) async landUseReportPage( @Session() session: { data?: SessionData }, - @Param("dtid") dtid, + @Param('dtid') dtid, @Req() req: Request, @Res() res: Response ) { - console.log('LUR report!') + console.log('LUR report!'); let isAdmin = false; - if ( - session.data && - session.data.activeAccount && - session.data.activeAccount.client_roles - ) { + if (session.data && session.data.activeAccount && session.data.activeAccount.client_roles) { for (let role of session.data.activeAccount.client_roles) { - if (role == "ticdi_admin") { + if (role == 'ticdi_admin') { isAdmin = true; } } } const title = - process.env.ticdi_environment == "DEVELOPMENT" - ? "DEVELOPMENT - " + PAGE_TITLES.INDEX - : PAGE_TITLES.INDEX; - const displayAdmin = isAdmin ? "Administration" : "-"; + process.env.ticdi_environment == 'DEVELOPMENT' ? 'DEVELOPMENT - ' + PAGE_TITLES.INDEX : PAGE_TITLES.INDEX; + const displayAdmin = isAdmin ? 'Administration' : '-'; await this.ttlsService.setWebadeToken(); let ttlsJSON, primaryContactName; try { - const response: any = await firstValueFrom( - this.ttlsService.callHttp(dtid) - ) + const response: any = await firstValueFrom(this.ttlsService.callHttp(dtid)) .then((res) => { return res; }) .catch((err) => { - console.log("callHttp failed"); + console.log('callHttp failed'); console.log(err); console.log(err.response.data); }); ttlsJSON = await this.ttlsService.sendToBackend(response); - ttlsJSON["cityProvPostal"] = this.ttlsService.concatCityProvPostal( + ttlsJSON['cityProvPostal'] = this.ttlsService.concatCityProvPostal( response.tenantAddr ? response.tenantAddr[0] : null ); if (ttlsJSON.inspected_date) { - ttlsJSON["inspected_date"] = this.ttlsService.formatInspectedDate( - ttlsJSON.inspected_date.toString() - ); + ttlsJSON['inspected_date'] = this.ttlsService.formatInspectedDate(ttlsJSON.inspected_date.toString()); } primaryContactName = ttlsJSON.licence_holder_name; - return res.render("index", { + return res.render('index', { title: title, - idirUsername: session.data.activeAccount - ? session.data.activeAccount.idir_username - : "", + idirUsername: session.data.activeAccount ? session.data.activeAccount.idir_username : '', primaryContactName: primaryContactName, displayAdmin: displayAdmin, message: ttlsJSON, - documentTypes: [ - "Land Use Report", - "Notice of Final Review", - "Grazing Lease", - ], + documentTypes: ['Land Use Report', 'Notice of Final Review', 'Grazing Lease'], prdid: ttlsJSON.id, }); } catch (err) { console.log(err); - return res.render("index",{ + return res.render('index', { title: title, - idirUsername: session.data.activeAccount - ? session.data.activeAccount.idir_username - : "", + idirUsername: session.data.activeAccount ? session.data.activeAccount.idir_username : '', primaryContactName: primaryContactName ? primaryContactName : null, displayAdmin: displayAdmin, message: ttlsJSON ? ttlsJSON : null, - documentTypes: [ - "Land Use Report", - "Notice of Final Review", - "Grazing Lease", - ], + documentTypes: ['Land Use Report', 'Notice of Final Review', 'Grazing Lease'], prdid: ttlsJSON ? ttlsJSON.id : null, error: err, }); } } - @Get("system-admin") - @Render("system-admin") + @Get('system-admin') + @Render('system-admin') @UseFilters(AuthenticationFilter) @UseGuards(AuthenticationGuard) @UseGuards(AdminGuard) async systemAdminPage(@Session() session: { data?: SessionData }) { let isAdmin = false; - if ( - session.data && - session.data.activeAccount && - session.data.activeAccount.client_roles - ) { + if (session.data && session.data.activeAccount && session.data.activeAccount.client_roles) { for (let role of session.data.activeAccount.client_roles) { - if (role == "ticdi_admin") { + if (role == 'ticdi_admin') { isAdmin = true; } } } - const displayAdmin = isAdmin ? "Administration" : "-"; + const displayAdmin = isAdmin ? 'Administration' : '-'; const title = - process.env.ticdi_environment == "DEVELOPMENT" - ? "DEVELOPMENT - " + PAGE_TITLES.ADMIN - : PAGE_TITLES.ADMIN; + process.env.ticdi_environment == 'DEVELOPMENT' ? 'DEVELOPMENT - ' + PAGE_TITLES.ADMIN : PAGE_TITLES.ADMIN; return { title: title, - idirUsername: session.data.activeAccount - ? session.data.activeAccount.idir_username - : "", + idirUsername: session.data.activeAccount ? session.data.activeAccount.idir_username : '', displayAdmin: displayAdmin, reportTypes: [ { reportType: REPORT_TYPES[0], reportIndex: 1 }, @@ -257,31 +201,24 @@ export class AppController { }; } - @Get("manage-templates") - @Render("manage-templates") + @Get('manage-templates') + @Render('manage-templates') @UseFilters(AuthenticationFilter) @UseGuards(AuthenticationGuard) @UseGuards(AdminGuard) - async adminPage( - @Session() session: { data?: SessionData }, - @Query("report") reportIndex - ) { + async adminPage(@Session() session: { data?: SessionData }, @Query('report') reportIndex) { let isAdmin = false; - if ( - session.data && - session.data.activeAccount && - session.data.activeAccount.client_roles - ) { + if (session.data && session.data.activeAccount && session.data.activeAccount.client_roles) { for (let role of session.data.activeAccount.client_roles) { - if (role == "ticdi_admin") { + if (role == 'ticdi_admin') { isAdmin = true; } } } - const displayAdmin = isAdmin ? "Administration" : "-"; + const displayAdmin = isAdmin ? 'Administration' : '-'; const title = - process.env.ticdi_environment == "DEVELOPMENT" - ? "DEVELOPMENT - " + PAGE_TITLES.MANAGE_TEMPLATES + process.env.ticdi_environment == 'DEVELOPMENT' + ? 'DEVELOPMENT - ' + PAGE_TITLES.MANAGE_TEMPLATES : PAGE_TITLES.MANAGE_TEMPLATES; let variantJsonArray = []; if (reportIndex == 2) { @@ -289,47 +226,37 @@ export class AppController { } return { title: title, - idirUsername: session.data.activeAccount - ? session.data.activeAccount.idir_username - : "", - primaryContactName: "", + idirUsername: session.data.activeAccount ? session.data.activeAccount.idir_username : '', + primaryContactName: '', displayAdmin: displayAdmin, variantJsonArray: variantJsonArray, }; } - @Get("search") - @Render("search") + @Get('search') + @Render('search') @UseFilters(AuthenticationFilter) @UseGuards(AuthenticationGuard) async searchPage(@Session() session: { data?: SessionData }) { let isAdmin = false; - if ( - session.data && - session.data.activeAccount && - session.data.activeAccount.client_roles - ) { + if (session.data && session.data.activeAccount && session.data.activeAccount.client_roles) { for (let role of session.data.activeAccount.client_roles) { - if (role == "ticdi_admin") { + if (role == 'ticdi_admin') { isAdmin = true; } } } - const displayAdmin = isAdmin ? "Administration" : "-"; + const displayAdmin = isAdmin ? 'Administration' : '-'; const title = - process.env.ticdi_environment == "DEVELOPMENT" - ? "DEVELOPMENT - " + PAGE_TITLES.SEARCH - : PAGE_TITLES.SEARCH; + process.env.ticdi_environment == 'DEVELOPMENT' ? 'DEVELOPMENT - ' + PAGE_TITLES.SEARCH : PAGE_TITLES.SEARCH; return { title: title, - idirUsername: session.data.activeAccount - ? session.data.activeAccount.idir_username - : "", + idirUsername: session.data.activeAccount ? session.data.activeAccount.idir_username : '', displayAdmin: displayAdmin, }; } - @Get("getHello") + @Get('getHello') getHello(): string { return this.appService.getHello(); } @@ -339,83 +266,71 @@ export class AppController { return this.appService.getHello(); } - @Get("/nfr/dtid/:dtid") - @Render("nfr") + @Get('/nfr/dtid/:dtid') + @Render('nfr') @UseFilters(AuthenticationFilter) @UseGuards(AuthenticationGuard) - redirectNFR(@Res() res: Response, @Param("dtid") dtid: number) { + redirectNFR(@Res() res: Response, @Param('dtid') dtid: number) { res.redirect(`/nfr/dtid/${dtid}/${encodeURI(NFR_VARIANTS.default)}`); return {}; } - @Get("/404") - @Render("404") + @Get('/404') + @Render('404') @UseFilters(AuthenticationFilter) @UseGuards(AuthenticationGuard) notFound(@Session() session: { data?: SessionData }) { let isAdmin = false; - if ( - session.data && - session.data.activeAccount && - session.data.activeAccount.client_roles - ) { + if (session.data && session.data.activeAccount && session.data.activeAccount.client_roles) { for (let role of session.data.activeAccount.client_roles) { - if (role == "ticdi_admin") { + if (role == 'ticdi_admin') { isAdmin = true; } } } - const displayAdmin = isAdmin ? "Administration" : "-"; + const displayAdmin = isAdmin ? 'Administration' : '-'; return { - title: "404 Not Found", - message: "Sorry, that page does not exist.", + title: '404 Not Found', + message: 'Sorry, that page does not exist.', displayAdmin: displayAdmin, }; } // grabs Grazing Lease display data and displays the grazing lease report page async getGrazingLeaseDisplayData(session, dtid, res) { - console.log("grazing lease"); + console.log('grazing lease'); let isAdmin = false; - if ( - session.data && - session.data.activeAccount && - session.data.activeAccount.client_roles - ) { + if (session.data && session.data.activeAccount && session.data.activeAccount.client_roles) { for (let role of session.data.activeAccount.client_roles) { - if (role == "ticdi_admin") { + if (role == 'ticdi_admin') { isAdmin = true; } } } const title = - process.env.ticdi_environment == "DEVELOPMENT" - ? "DEVELOPMENT - " + PAGE_TITLES.GRAZING_LEASE + process.env.ticdi_environment == 'DEVELOPMENT' + ? 'DEVELOPMENT - ' + PAGE_TITLES.GRAZING_LEASE : PAGE_TITLES.GRAZING_LEASE; - const displayAdmin = isAdmin ? "Administration" : "-"; + const displayAdmin = isAdmin ? 'Administration' : '-'; await this.ttlsService.setWebadeToken(); let ttlsJSON, primaryContactName; try { - const response: any = await firstValueFrom( - this.ttlsService.callHttp(dtid) - ) + const response: any = await firstValueFrom(this.ttlsService.callHttp(dtid)) .then((res) => { return res; }) .catch((err) => { - console.log("callHttp failed"); + console.log('callHttp failed'); console.log(err); console.log(err.response.data); }); ttlsJSON = await this.ttlsService.formatNFRData(response); primaryContactName = ttlsJSON.licenceHolderName; const interestedParties = nfrInterestedParties(response.tenantAddr); - ttlsJSON["interestedParties"] = interestedParties; - return res.render("grazing-lease", { + ttlsJSON['interestedParties'] = interestedParties; + return res.render('grazing-lease', { title: title, - idirUsername: session.data.activeAccount - ? session.data.activeAccount.idir_username - : "", + idirUsername: session.data.activeAccount ? session.data.activeAccount.idir_username : '', primaryContactName: primaryContactName, displayAdmin: displayAdmin, message: ttlsJSON, @@ -423,11 +338,9 @@ export class AppController { }); } catch (err) { console.log(err); - return res.render("grazing-lease", { + return res.render('grazing-lease', { title: title, - idirUsername: session.data.activeAccount - ? session.data.activeAccount.idir_username - : "", + idirUsername: session.data.activeAccount ? session.data.activeAccount.idir_username : '', primaryContactName: primaryContactName ? primaryContactName : null, displayAdmin: displayAdmin, message: ttlsJSON ? ttlsJSON : null, @@ -441,39 +354,24 @@ export class AppController { async getNfrDisplayData(session, dtid, variantName, res) { let ttlsJSON, primaryContactName, nfrData; let isAdmin = false; - if ( - session.data && - session.data.activeAccount && - session.data.activeAccount.client_roles - ) { + if (session.data && session.data.activeAccount && session.data.activeAccount.client_roles) { for (let role of session.data.activeAccount.client_roles) { - if (role == "ticdi_admin") { + if (role == 'ticdi_admin') { isAdmin = true; } } } const title = - process.env.ticdi_environment == "DEVELOPMENT" - ? "DEVELOPMENT - " + PAGE_TITLES.NOFR - : PAGE_TITLES.NOFR; - const displayAdmin = isAdmin ? "Administration" : "-"; - const groupMaxJsonArray = await this.reportService.getGroupMaxByVariant( - "NOTICE OF FINAL REVIEW" - ); + process.env.ticdi_environment == 'DEVELOPMENT' ? 'DEVELOPMENT - ' + PAGE_TITLES.NOFR : PAGE_TITLES.NOFR; + const displayAdmin = isAdmin ? 'Administration' : '-'; + const groupMaxJsonArray = await this.reportService.getGroupMaxByVariant('NOTICE OF FINAL REVIEW'); try { - const nfrDataObject = await this.reportService.getActiveNfrDataByDtid( - dtid - ); + const nfrDataObject = await this.reportService.getActiveNfrDataByDtid(dtid); nfrData = nfrDataObject.nfrData; - const provisionIds = nfrDataObject.provisionIds - ? nfrDataObject.provisionIds - : []; - const mandatoryProvisionIds = - await this.reportService.getMandatoryProvisionsByVariant(variantName); + const provisionIds = nfrDataObject.provisionIds ? nfrDataObject.provisionIds : []; + const mandatoryProvisionIds = await this.reportService.getMandatoryProvisionsByVariant(variantName); await this.ttlsService.setWebadeToken(); - const response: any = await firstValueFrom( - this.ttlsService.callHttp(dtid) - ) + const response: any = await firstValueFrom(this.ttlsService.callHttp(dtid)) .then((res) => { return res; }) @@ -483,7 +381,7 @@ export class AppController { ttlsJSON = await this.ttlsService.formatNFRData(response); primaryContactName = ttlsJSON.licenceHolderName; const interestedParties = nfrInterestedParties(response.tenantAddr); - ttlsJSON["interestedParties"] = interestedParties; + ttlsJSON['interestedParties'] = interestedParties; let selectedVariant = 0; switch (variantName.toLowerCase()) { case NFR_VARIANTS.default.toLowerCase(): { @@ -507,11 +405,9 @@ export class AppController { break; } } - return res.render("nfr", { + return res.render('nfr', { title: title, - idirUsername: session.data.activeAccount - ? session.data.activeAccount.idir_username - : "", + idirUsername: session.data.activeAccount ? session.data.activeAccount.idir_username : '', primaryContactName: primaryContactName, displayAdmin: displayAdmin, message: ttlsJSON, @@ -524,11 +420,9 @@ export class AppController { }); } catch (err) { console.log(err); - return res.render("nfr", { + return res.render('nfr', { title: title, - idirUsername: session.data.activeAccount - ? session.data.activeAccount.idir_username - : "", + idirUsername: session.data.activeAccount ? session.data.activeAccount.idir_username : '', primaryContactName: primaryContactName ? primaryContactName : null, displayAdmin: displayAdmin, message: ttlsJSON ? ttlsJSON : null, From a75d21d27eaea9425f5e74bf7e8e13139ad55e7a Mon Sep 17 00:00:00 2001 From: mgtennant <100305096+mgtennant@users.noreply.github.com> Date: Wed, 24 Jan 2024 09:59:41 -0800 Subject: [PATCH 4/9] redeploying --- backend/src/app.controller.ts | 1 - frontend/src/app.controller.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/backend/src/app.controller.ts b/backend/src/app.controller.ts index 469130a4..a121c70c 100644 --- a/backend/src/app.controller.ts +++ b/backend/src/app.controller.ts @@ -10,7 +10,6 @@ export class AppController { return this.appService.getHello(); } - // @Get() getHello2(): string { return this.appService.getHello(); diff --git a/frontend/src/app.controller.ts b/frontend/src/app.controller.ts index 40aaf80e..fa8319c8 100644 --- a/frontend/src/app.controller.ts +++ b/frontend/src/app.controller.ts @@ -13,7 +13,6 @@ import { Request, Response } from 'express'; import { ReportService } from './report/report.service'; import { nfrInterestedParties } from '../utils/util'; -// let requestUrl: string; let requestConfig: AxiosRequestConfig; From 38eeef34478e9bab02a4486051e499daf45e1527 Mon Sep 17 00:00:00 2001 From: mgtennant <100305096+mgtennant@users.noreply.github.com> Date: Wed, 24 Jan 2024 13:45:40 -0800 Subject: [PATCH 5/9] sort nfr legal descriptions by parcel id --- backend/src/app.controller.ts | 2 +- frontend/src/report/report.service.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/src/app.controller.ts b/backend/src/app.controller.ts index a121c70c..fceedc37 100644 --- a/backend/src/app.controller.ts +++ b/backend/src/app.controller.ts @@ -9,7 +9,7 @@ export class AppController { getHello(): string { return this.appService.getHello(); } - + // @Get() getHello2(): string { return this.appService.getHello(); diff --git a/frontend/src/report/report.service.ts b/frontend/src/report/report.service.ts index d153e365..d85f19a1 100644 --- a/frontend/src/report/report.service.ts +++ b/frontend/src/report/report.service.ts @@ -350,6 +350,7 @@ export class ReportService { const interestParcels = rawData.interestParcel; let concatLegalDescriptions = ''; if (interestParcels && interestParcels.length > 0) { + interestParcels.sort((a, b) => b.interestParcelId - a.interestParcelId); let legalDescArray = []; for (let ip of interestParcels) { if (ip.legalDescription && ip.legalDescription != '') { From 24f5f5786d050a82bbda44947ae16993c41aea3c Mon Sep 17 00:00:00 2001 From: mgtennant <100305096+mgtennant@users.noreply.github.com> Date: Mon, 11 Mar 2024 11:25:48 -0700 Subject: [PATCH 6/9] update report service search function --- frontend/src/report/report.service.ts | 94 +++++++++++++-------------- 1 file changed, 44 insertions(+), 50 deletions(-) diff --git a/frontend/src/report/report.service.ts b/frontend/src/report/report.service.ts index d85f19a1..369f9c4e 100644 --- a/frontend/src/report/report.service.ts +++ b/frontend/src/report/report.service.ts @@ -689,6 +689,7 @@ export class ReportService { } async getGroupMaxByVariant(variantName: string): Promise { + console.log(variantName); const url = `${hostname}:${port}/nfr-provision/get-group-max/variant/${variantName}`; return await axios.get(url).then((res) => { return res.data; @@ -732,59 +733,52 @@ export class ReportService { async getNFRData() { const nfrDataUrl = `${hostname}:${port}/nfr-data`; const templateUrl = `${hostname}:${port}/document-template/nfr-template-info`; - const nfrData = await axios - .get(nfrDataUrl) - .then((res) => { - return res.data; - }) - .catch((err) => console.log(err.response.data)); - const templateIds = []; - for (let entry of nfrData) { - templateIds.push(entry.template_id); + + // get NFR data + let nfrData; + try { + const response = await axios.get(nfrDataUrl); + nfrData = response.data; + } catch (err) { + console.log(err.response.data); + return; } - const allTemplates: { - id: number; - file_name: string; - active_flag: boolean; - is_deleted: boolean; - template_version: number; - }[] = await axios - .post(templateUrl, templateIds) - .then((res) => { - return res.data; - }) - .catch((err) => console.log(err.response.data)); - // Combine the corresponding templates with the nfr data. - const combinedArray = []; - - let i = 0; - let j = 0; - - while (i < allTemplates.length && j < nfrData.length) { - const template = allTemplates[i]; - const nfr = nfrData[j]; - - if (template.id === nfr.template_id) { - if (!template.is_deleted) { - combinedArray.push({ - dtid: nfr.dtid, - version: template.template_version, - file_name: template.file_name, - updated_date: nfr.update_timestamp.split('T')[0], - status: nfr.status, - active: template.active_flag, - nfr_id: nfr.id, - variant_name: nfr.variant_name, - }); - } - j++; - } else if (template.id < nfr.template_id) { - i++; - } else { - j++; - } + // get template IDs from NFR data + const templateIds = nfrData.map((entry) => entry.template_id); + + // get templates using template IDs + let allTemplates; + try { + const response = await axios.post(templateUrl, templateIds); + allTemplates = response.data; + } catch (err) { + console.log(err.response.data); + return; } + + // filter out deleted templates and create a lookup table + const templatesLookup = allTemplates.reduce((acc, template) => { + if (!template.is_deleted) { + acc[template.id] = template; + } + return acc; + }, {}); + + // combine NFR data with their corresponding templates + const combinedArray = nfrData + .filter((nfr) => templatesLookup[nfr.template_id]) + .map((nfr) => ({ + dtid: nfr.dtid, + version: templatesLookup[nfr.template_id].template_version, + file_name: templatesLookup[nfr.template_id].file_name, + updated_date: nfr.update_timestamp.split('T')[0], + status: nfr.status, + active: templatesLookup[nfr.template_id].active_flag, + nfr_id: nfr.id, + variant_name: nfr.variant_name, + })); + return combinedArray; } From 41e46de12054ce9bb143c0275f07cde70aafa712 Mon Sep 17 00:00:00 2001 From: mgtennant <100305096+mgtennant@users.noreply.github.com> Date: Mon, 11 Mar 2024 11:29:05 -0700 Subject: [PATCH 7/9] remove a console.log --- frontend/src/report/report.service.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/report/report.service.ts b/frontend/src/report/report.service.ts index 369f9c4e..c65b178d 100644 --- a/frontend/src/report/report.service.ts +++ b/frontend/src/report/report.service.ts @@ -689,7 +689,6 @@ export class ReportService { } async getGroupMaxByVariant(variantName: string): Promise { - console.log(variantName); const url = `${hostname}:${port}/nfr-provision/get-group-max/variant/${variantName}`; return await axios.get(url).then((res) => { return res.data; From b0df40ab46fc2d9bf44d820c4c0dc65dfbc47bb5 Mon Sep 17 00:00:00 2001 From: Shiv Satya Date: Wed, 13 Mar 2024 12:06:50 -0700 Subject: [PATCH 8/9] Jira Ticket TICDI-312 & TICDI-326 --- frontend/package-lock.json | 89 ++++++- frontend/package.json | 3 +- frontend/public/css/new.css | 4 + frontend/public/js/manage-templates.js | 29 ++- frontend/src/app/App.tsx | 4 + .../manage-templates/TemplateInfoTable.tsx | 17 +- frontend/src/app/content/Content.tsx | 7 + frontend/src/app/content/display/Header.tsx | 2 +- .../src/app/content/pages/ManageTemplates.tsx | 59 +++++ .../content/pages/SystemAdministration.tsx | 66 +++++ .../documentpreview/ContactInfoDisplay.tsx | 48 ++++ .../documentpreview/CustomCollapsible.tsx | 66 +++++ .../documentpreview/DocumentPreview.scss | 199 +++++++++++++++ .../pages/documentpreview/DocumentPreview.tsx | 227 ++++++++++++++++++ .../documentpreview/DocumentPreviewForm.tsx | 114 +++++++++ .../GroupSelectionAndProvisions.scss | 123 ++++++++++ .../GroupSelectionAndProvisions.tsx | 59 +++++ .../InterestedPartiesDisplay.tsx | 50 ++++ .../documentpreview/LicenseDetailDisplay.tsx | 48 ++++ .../pages/documentpreview/ProvisionsTable.tsx | 72 ++++++ frontend/src/app/types/types.ts | 1 + frontend/src/app/util/constants.ts | 14 ++ 22 files changed, 1287 insertions(+), 14 deletions(-) create mode 100644 frontend/src/app/content/pages/ManageTemplates.tsx create mode 100644 frontend/src/app/content/pages/SystemAdministration.tsx create mode 100644 frontend/src/app/content/pages/documentpreview/ContactInfoDisplay.tsx create mode 100644 frontend/src/app/content/pages/documentpreview/CustomCollapsible.tsx create mode 100644 frontend/src/app/content/pages/documentpreview/DocumentPreview.scss create mode 100644 frontend/src/app/content/pages/documentpreview/DocumentPreview.tsx create mode 100644 frontend/src/app/content/pages/documentpreview/DocumentPreviewForm.tsx create mode 100644 frontend/src/app/content/pages/documentpreview/GroupSelectionAndProvisions.scss create mode 100644 frontend/src/app/content/pages/documentpreview/GroupSelectionAndProvisions.tsx create mode 100644 frontend/src/app/content/pages/documentpreview/InterestedPartiesDisplay.tsx create mode 100644 frontend/src/app/content/pages/documentpreview/LicenseDetailDisplay.tsx create mode 100644 frontend/src/app/content/pages/documentpreview/ProvisionsTable.tsx diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 1d19ad5a..19bf305c 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -28,6 +28,10 @@ "react-scripts": "5.0.1", "redux": "^5.0.1", "web-vitals": "^2.1.4" + }, + "devDependencies": { + "@babel/plugin-proposal-private-property-in-object": "^7.21.11", + "sass": "^1.71.1" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -656,9 +660,17 @@ } }, "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0-placeholder-for-preset-env.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", - "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "version": "7.21.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.11.tgz", + "integrity": "sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-property-in-object instead.", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.21.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, "engines": { "node": ">=6.9.0" }, @@ -1902,6 +1914,17 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/preset-env/node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/preset-env/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -9634,6 +9657,12 @@ "url": "https://opencollective.com/immer" } }, + "node_modules/immutable": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", + "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==", + "devOptional": true + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -15936,6 +15965,23 @@ "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-13.0.0.tgz", "integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==" }, + "node_modules/sass": { + "version": "1.71.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.71.1.tgz", + "integrity": "sha512-wovtnV2PxzteLlfNzbgm1tFXPLoZILYAMJtvoXXkD7/+1uP41eKkIt1ypWq5/q2uT94qHjXehEYfmjKOvjL9sg==", + "devOptional": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/sass-loader": { "version": "12.6.0", "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", @@ -19122,10 +19168,16 @@ } }, "@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0-placeholder-for-preset-env.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", - "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", - "requires": {} + "version": "7.21.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.11.tgz", + "integrity": "sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.21.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + } }, "@babel/plugin-syntax-async-generators": { "version": "7.8.4", @@ -19921,6 +19973,12 @@ "semver": "^6.3.1" }, "dependencies": { + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "requires": {} + }, "semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -25488,6 +25546,12 @@ "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==" }, + "immutable": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", + "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==", + "devOptional": true + }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -29838,6 +29902,17 @@ "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-13.0.0.tgz", "integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==" }, + "sass": { + "version": "1.71.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.71.1.tgz", + "integrity": "sha512-wovtnV2PxzteLlfNzbgm1tFXPLoZILYAMJtvoXXkD7/+1uP41eKkIt1ypWq5/q2uT94qHjXehEYfmjKOvjL9sg==", + "devOptional": true, + "requires": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + } + }, "sass-loader": { "version": "12.6.0", "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 91f12c85..b66f7eb5 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -25,7 +25,8 @@ "web-vitals": "^2.1.4" }, "devDependencies": { - "@babel/plugin-proposal-private-property-in-object": "^7.21.11" + "@babel/plugin-proposal-private-property-in-object": "^7.21.11", + "sass": "^1.71.1" }, "scripts": { "start": "react-scripts start", diff --git a/frontend/public/css/new.css b/frontend/public/css/new.css index 049d5e71..9f125ba2 100644 --- a/frontend/public/css/new.css +++ b/frontend/public/css/new.css @@ -17,3 +17,7 @@ hr { background-color: #000000; height: 1px; } + +.boldText { + font-weight: bold; +} diff --git a/frontend/public/js/manage-templates.js b/frontend/public/js/manage-templates.js index 1a181bfd..f5cbb487 100644 --- a/frontend/public/js/manage-templates.js +++ b/frontend/public/js/manage-templates.js @@ -51,13 +51,14 @@ $(document).ready(function () { { data: "file_name" }, { data: "update_timestamp" }, { data: "active_flag" }, + { data: "preview" }, { data: "view" }, { data: "remove" }, { data: "id" }, ], columnDefs: [ { - targets: [0, 1, 2, 3, 4, 5, 6], + targets: [0, 1, 2, 3, 4, 5, 6, 7], render: function (data, type, row, meta) { if (type === "display") { var columnTypes = [ @@ -65,6 +66,7 @@ $(document).ready(function () { "file_name", "update_timestamp", "active_flag", + "preview", "view", "remove", "id", @@ -81,6 +83,8 @@ $(document).ready(function () { return ` + ), + header: () => null, + meta: { customCss: { width: '10%' } }, + }), columnHelper.accessor('view', { id: 'view', cell: (info) => ( @@ -103,11 +116,11 @@ const TemplateInfoTable: React.FC = ({ reportType, refre variant="info" onClick={() => handleDownloadTemplate(info.row.original.id, info.row.original.file_name)} > - View + View Doc ), header: () => null, - meta: { customCss: { width: '7%' } }, + meta: { customCss: { width: '12%' } }, }), columnHelper.accessor('remove', { id: 'remove', diff --git a/frontend/src/app/content/Content.tsx b/frontend/src/app/content/Content.tsx index 487a1fa5..c9b9433e 100644 --- a/frontend/src/app/content/Content.tsx +++ b/frontend/src/app/content/Content.tsx @@ -4,6 +4,9 @@ import SearchPage from './pages/SearchPage'; import AdminPage from './pages/AdminPage'; import ManageTemplatesPage from './pages/ManageTemplatesPage'; import { CURRENT_REPORT_PAGES } from '../util/constants'; +import DocumentPreview from './pages/documentpreview/DocumentPreview'; +import ManageTemplates from './pages/ManageTemplates'; +import SystemAdministration from './pages/SystemAdministration'; interface ContentProps { pageTitle: string; @@ -20,9 +23,13 @@ const Content: FC = ({ pageTitle }) => { {Object.values(CURRENT_REPORT_PAGES).includes(pageTitle) && ( )} + {pageTitle === 'Search' && } {pageTitle === 'System Administration' && } {pageTitle === 'Manage Templates' && } + {pageTitle === 'Document Preview' && } + {pageTitle === 'Select Manage Templates' && } + {pageTitle === 'System Administration Menu' && } diff --git a/frontend/src/app/content/display/Header.tsx b/frontend/src/app/content/display/Header.tsx index 35cd04fe..d84fbaeb 100644 --- a/frontend/src/app/content/display/Header.tsx +++ b/frontend/src/app/content/display/Header.tsx @@ -42,7 +42,7 @@ const Header: FC = ({ isAdmin, idirUsername }) => {
{isAdmin && ( diff --git a/frontend/src/app/content/pages/ManageTemplates.tsx b/frontend/src/app/content/pages/ManageTemplates.tsx new file mode 100644 index 00000000..6b3e982d --- /dev/null +++ b/frontend/src/app/content/pages/ManageTemplates.tsx @@ -0,0 +1,59 @@ +import { FC, useState } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { REPORT_TYPES } from '../../util/constants'; + +const ManageTemplates: FC = () => { + + const [selectedReport, setSelectedReport] = useState('0'); + const navigate = useNavigate(); + + const selectedReportHandler = (event: React.ChangeEvent) => { + setSelectedReport(event.target.value); + }; + + const manageReportsHandler = () => { + navigate(`/manage-templates/${selectedReport}`); + }; + + + return ( + <> +
+

Manage Templates

+
+
+
+

Select a Template:

+
+
+
+ +
+
+ +
+
+ + ); +}; + +export default ManageTemplates; \ No newline at end of file diff --git a/frontend/src/app/content/pages/SystemAdministration.tsx b/frontend/src/app/content/pages/SystemAdministration.tsx new file mode 100644 index 00000000..6d0b243b --- /dev/null +++ b/frontend/src/app/content/pages/SystemAdministration.tsx @@ -0,0 +1,66 @@ +import React from 'react'; +import { useNavigate } from 'react-router-dom'; + +interface ManagementOption { + id: string; + label: string; +} + +const managementOptions: ManagementOption[] = [ + { id: 'administrators', label: 'Manage Administrators' }, + { id: 'documentTypes', label: 'Manage Document Types' }, + { id: 'templates', label: 'Manage Templates' }, + { id: 'provisions', label: 'Manage Provisions' }, +]; + +const SystemAdministration: React.FC = () => { + const navigate = useNavigate(); + + + const handleGoClick = (optionId: string) => { + switch (optionId) { + case 'administrators': + console.log('Go to Manage Administrators'); + navigate(`/system-admin`); + break; + case 'documentTypes': + console.log('Go to Manage Document Types'); + break; + case 'templates': + console.log('Go to Manage Templates'); + navigate(`/manage-templates-select`); + break; + case 'provisions': + console.log('Go to Manage Provisions'); + break; + default: + console.log('Unknown option'); + break; + } + }; + + return ( +
+

System Administration

+
+ {managementOptions.map((option) => ( +
+ {option.label} + +
+ ))} +
+ ); +}; + +export default SystemAdministration; diff --git a/frontend/src/app/content/pages/documentpreview/ContactInfoDisplay.tsx b/frontend/src/app/content/pages/documentpreview/ContactInfoDisplay.tsx new file mode 100644 index 00000000..3e3763a6 --- /dev/null +++ b/frontend/src/app/content/pages/documentpreview/ContactInfoDisplay.tsx @@ -0,0 +1,48 @@ +import React from 'react'; +import { Row, Col } from 'react-bootstrap'; + +interface ContactInfoProps { + contactName: string; + organizationUnit: string | number; + incorporationNumber: string | number; + emailAddress: string; + dateInspected: string; +} + +const ContactInfoDisplay: React.FC = ({ + contactName, + organizationUnit, + incorporationNumber, + emailAddress, + dateInspected, +}) => { + return ( +
+
+ +
+
Contact or Agent Name
+
{contactName}
+ +
Organization Unit
+
{organizationUnit}
+ +
Incorporation Number
+
{incorporationNumber}
+
+ + +
+
Email Address
+
{emailAddress}
+ +
Date Inspected
+
{dateInspected}
+
+ +
+
+ ); +}; + +export default ContactInfoDisplay; diff --git a/frontend/src/app/content/pages/documentpreview/CustomCollapsible.tsx b/frontend/src/app/content/pages/documentpreview/CustomCollapsible.tsx new file mode 100644 index 00000000..4e28f623 --- /dev/null +++ b/frontend/src/app/content/pages/documentpreview/CustomCollapsible.tsx @@ -0,0 +1,66 @@ +import React, { FC, useState, useEffect } from 'react'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { IconProp } from '@fortawesome/fontawesome-svg-core'; +import { faPlus, faMinus } from '@fortawesome/fontawesome-free-solid'; +import './DocumentPreview.scss'; + + +interface CustomCollapsibleProps { + title: string; + children: React.ReactNode; + isOpen: boolean; + toggleCollapsible: () => void; + isSpanRequired: boolean +} + +const CustomCollapsible: FC = ({ title, children, isOpen, toggleCollapsible, isSpanRequired }) => { + const [isOpenonClick, setIsOpenOnClick] = useState(isOpen); + const icon = isOpenonClick ? faMinus : (faPlus as IconProp); + + const contentStyle = { + display: isOpenonClick ? 'block' : 'none', + }; + + + const handleClick: React.MouseEventHandler = () => { + console.log('Select was clicked'); + }; + + + const handleChange: React.ChangeEventHandler = (e) => { + console.log('Selected value:', e.target.value); + }; + const toggleCollapsibleOnClick = () => { + //setIsInternalClick(true); + setIsOpenOnClick(!isOpenonClick); + }; + + useEffect(() => { + setIsOpenOnClick(isOpen); + }, [isOpen]); + + + return ( +
+
+ +
{title}
+ {isSpanRequired ?
+ + + Max for This Group is X +
: ""} +
+ +
+
{children}
+
+ ); +}; + +export default CustomCollapsible; diff --git a/frontend/src/app/content/pages/documentpreview/DocumentPreview.scss b/frontend/src/app/content/pages/documentpreview/DocumentPreview.scss new file mode 100644 index 00000000..1483ee22 --- /dev/null +++ b/frontend/src/app/content/pages/documentpreview/DocumentPreview.scss @@ -0,0 +1,199 @@ +.Collapsible { + background: #fff; + box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.1); + border: 1px solid #ddd; + margin-bottom: 20px; + padding: 20px; + border-radius: 4px; + } + + .Collapsible-title { + margin: 0; + padding-bottom: 10px; + font-size: 18px; + color: #333; + border-bottom: 1px solid #e7e7e7; + display: flex; + align-items: center; + justify-content: space-between; + cursor: pointer; + border-bottom:2px solid; + background-color: #000000 !important; + } + + .Collapsible-content { + padding-top: 20px; + } + .Collapsible-heading_divider{ + margin-bottom: 20px; + border-bottom:2px solid; + background-color: #000000 !important; + + } + + .group-select-container { + .group-select-label, + .group-select { + margin-left: 20px; + font-size: 14px; + } + + .max-group-text { + margin-left: 20px; + font-size: 12px; + } +} + +.text_size{ + font-size: 18px; +} + +.margin_bottom{ + margin-bottom: 20px ; +} + .document-preview { + max-width: 100%; + margin: auto; + font-family: Arial, sans-serif; + + &__title { + font-size: 24px; + margin-bottom: 20px; + } + + &__divider { + margin-bottom: 20px; + border-bottom:5px solid; + background-color: #000000 !important; + } + + &__form { + .form-control { + margin-bottom: 10px; + } + + .button-group { + display: flex; + gap: 10px; + align-items: center; + justify-content: flex-start; + } + } + + .button { + padding: 10px 20px; + border: none; + border-radius: 4px; + cursor: pointer; + font-weight: bold; + &--retrieve { + background-color: limegreen; + color: white; + } + &--clear { + background-color: #f8f9fa; + color: #212529; + border: 1px solid #ced4da; + } + } + + .form-static-text { + padding: 8px; + background-color: #e9ecef; + border-radius: 4px; + } + + .form-label { + display: block; + margin-bottom: 5px; + font-weight: bold; + } + } + +.createDocument{ + margin-right: 5px ; + font-weight: bold; + font-weight: 18px; + +} +.select{ + padding: 10px; + border: 1px solid #ccc; + border-radius: 5px; +} + +$table-cell-padding: 0.5rem; +$input-border-color: #ced4da; +$input-border-radius: 0.25rem; +$button-background-save: #28a745; +$button-background-generate: #007bff; + + +table { + width: 100%; + border-collapse: collapse; + + th { + text-align: left; + padding: $table-cell-padding; + } + + td { + padding: $table-cell-padding; + + input[type="text"] { + width: 100%; + padding: $table-cell-padding; + border: 1px solid $input-border-color; + border-radius: $input-border-radius; + + &:focus { + outline: none; + border-color: darken($input-border-color, 10%); + } + } + } +} + + +label { + display: block; + margin: 0.5rem 0; +} + +input[type="text"] { + // width: 100%; + padding: $table-cell-padding; + margin-bottom: 1rem; + border: 1px solid $input-border-color; + border-radius: $input-border-radius; +} + + +.button { + padding: $table-cell-padding 1rem; + border: none; + border-radius: $input-border-radius; + font-weight: bold; + cursor: pointer; + margin-right: 0.5rem; + color: #fff; + + &--save { + background-color: $button-background-save; + } + + &--generate { + background-color: $button-background-generate; + } +} + + +.variable--algin{ + display: flex; + margin-left: 30%; + font-weight: bold; +} +.help--algin{ + margin-right: 10px; +} diff --git a/frontend/src/app/content/pages/documentpreview/DocumentPreview.tsx b/frontend/src/app/content/pages/documentpreview/DocumentPreview.tsx new file mode 100644 index 00000000..8788882b --- /dev/null +++ b/frontend/src/app/content/pages/documentpreview/DocumentPreview.tsx @@ -0,0 +1,227 @@ +import React, { useState } from 'react'; +import { getData, getNfrProvisionsByVariantDtid, getNfrVariablesByVariantDtid } from '../../../common/report'; +import DocumentPreviewForm from './DocumentPreviewForm'; +import ContactInfoDisplay from './ContactInfoDisplay'; +import LicenseDetailDisplay from './LicenseDetailDisplay'; +import InterestedPartiesDisplay from './InterestedPartiesDisplay'; +import GroupSelectionAndProvisions from './GroupSelectionAndProvisions'; +import ProvisionsTable from './ProvisionsTable'; +import './DocumentPreview.scss'; +import CustomCollapsible from './CustomCollapsible'; + + +interface DocumentPreviewResponse { + dtid: number; + fileNum: string; + primaryContactName: string; + contactName: string; + orgUnit: string; + primaryContactEmail: string; + primaryContactPhone: string; + contactEmail: string; + contactPhoneNumber: string; + incorporationNum: string; + inspectionDate: string; + type: string; + subType: string; + purpose: string; + subPurpose: string; + mailingAddress1: string; + mailingAddress2: string; + mailingAddress3: string; + locLand: string; + areaList: Array<{ + areaInHectares: number; + legalDescription: string; + }>; + interestedParties: Array<{ + clientName: string; + address: string; + }>; +} + + +interface Provision { + type: string; + provision: string; + freeText: string; + category: string; + included: boolean; +} + +type ProvisionType = { + id: number; + name: string; + freeText: string; + category: string; + included: boolean; +}; + +const DocumentPreview: React.FC = () => { + const [tenureFileNumber, setTenureFileNumber] = useState(''); + const [dtid, setDtid] = useState(''); //928437 + const [documentPreviewResponse, setDocumentPreviewResponse] = useState(null); + const [primaryContactName, setPrimaryContactName] = useState(''); + const [selectedGroup, setSelectedGroup] = useState('110'); + + const [variableName, setVariableName] = useState(''); + const [helpText, setHelpText] = useState(''); + + const handleSaveForLater = () => { + // Implement save for later logic + console.log('Saved for later:'); + }; + + const handleGenerateDocument = () => { + console.log('Generate document with:'); + }; + + const provisionsDummy: ProvisionType[] = [ + { id: 1, name: 'STANDARD LICENCE PROVISION 1', freeText: 'Lorem ipsum...', category: '', included: true }, + { id: 2, name: 'STANDARD LICENCE PROVISION 2', freeText: 'Lorem ipsum...', category: '', included: true }, + { id: 3, name: 'STANDARD LICENCE PROVISION 3', freeText: 'Lorem ipsum...', category: '', included: false }, + ]; + + const handleClear = () => { + setTenureFileNumber(''); + setDtid(''); + setIsOpen(false) + setDocumentPreviewResponse(null) + }; + + const [provisions, setProvisions] = useState([ + { type: 'STANDARD LICENSE PROVISION 1', freeText: '', category: '', included: false, provision: 'Lorem ipsum...' }, + { type: 'STANDARD LICENSE PROVISION 2', freeText: '', category: '', included: false, provision: 'Lorem ipsum...' }, + { type: 'STANDARD LICENSE PROVISION 3', freeText: '', category: '', included: false, provision: 'Lorem ipsum...' }, + ]); + + const [documentType, setDocumentType] = useState('STANDARD_LICENSE'); + + + const handleCheckboxChange = (index: number) => { + provisions[index].included = !provisions[index].included; + }; + + + + const fetchData = async () => { + const nfrData = await getData(parseInt(dtid)) as DocumentPreviewResponse; + if (nfrData) { + setDocumentPreviewResponse(nfrData) + const dataProvisions = await getNfrProvisionsByVariantDtid("NOTICE OF FINAL REVIEW", 928437); + const dataVariables = await getNfrVariablesByVariantDtid("NOTICE OF FINAL REVIEW", 928437); + setIsOpen(true); + } + }; + + const handleRetrieve = () => { + if (tenureFileNumber !== "" && dtid !== "") { + fetchData(); + } + }; + const [isOpen, setIsOpen] = useState(false); + + const toggleCollapsible = () => setIsOpen(!isOpen); + + + + + + return ( +
+ + + + + {documentPreviewResponse !== null ? : ""} + + + + + {documentPreviewResponse !== null ? : ""} + + + + + {documentPreviewResponse !== null ? : ""} + + +
+

Create Document

+
+
+ + +
+
+ + + + + + + + + + +
+ + +
+
+ ); +}; + +export default DocumentPreview; diff --git a/frontend/src/app/content/pages/documentpreview/DocumentPreviewForm.tsx b/frontend/src/app/content/pages/documentpreview/DocumentPreviewForm.tsx new file mode 100644 index 00000000..f366fb46 --- /dev/null +++ b/frontend/src/app/content/pages/documentpreview/DocumentPreviewForm.tsx @@ -0,0 +1,114 @@ +import React, { useState } from 'react'; +import { Row, Col } from 'react-bootstrap'; +import './DocumentPreview.scss'; + +interface DocumentPreviewFormProps { + tenureFileNumber: string; + dtid: string; + primaryContactName: string; + //handleRetrieve: () => void; + onValidatedRetrieve: () => void; + setTenureFileNumber: (value: string) => void; + setDtid: (value: string) => void; + handleClear: () => void; +} + +const DocumentPreviewForm: React.FC = ({ + tenureFileNumber, + dtid, + primaryContactName, + //handleRetrieve, + onValidatedRetrieve, + setTenureFileNumber, + setDtid, + handleClear, +}) => { + + + const [errors, setErrors] = useState<{ [key: string]: string }>({ + tenureFileNumber: '', + dtid: '', + }); + const isNumeric = (value: string) => /^-?\d+(\.\d+)?$/.test(value); + + const validateFields = (): boolean => { + let newErrors = { tenureFileNumber: '', dtid: '' }; + + if (!tenureFileNumber) { + newErrors.tenureFileNumber = 'Tenure File Number is required.'; + } else if (!isNumeric(tenureFileNumber)) { + newErrors.tenureFileNumber = 'Tenure File Number must be a number.'; + } + + if (!dtid) { + newErrors.dtid = 'DTID is required.'; + } else if (!isNumeric(dtid)) { + newErrors.dtid = 'DTID must be a number.'; + } + setErrors(newErrors); + return !Object.values(newErrors).some(error => error !== ''); + }; + + const handleRetrieveClick = () => { + const isValid = validateFields(); + if (isValid) { + onValidatedRetrieve(); + } + }; + + return ( +
+

Document Preview

+
+ + + + + + + setTenureFileNumber(e.target.value)} + /> + {errors.tenureFileNumber &&
{errors.tenureFileNumber}
} + + + + + +
+ + + + + + + setDtid(e.target.value)} + /> + {errors.dtid &&
{errors.dtid}
} + +
+ + + + + + +
{primaryContactName}
+ +
+
+ + + ); +}; + +export default DocumentPreviewForm; diff --git a/frontend/src/app/content/pages/documentpreview/GroupSelectionAndProvisions.scss b/frontend/src/app/content/pages/documentpreview/GroupSelectionAndProvisions.scss new file mode 100644 index 00000000..c4c701bb --- /dev/null +++ b/frontend/src/app/content/pages/documentpreview/GroupSelectionAndProvisions.scss @@ -0,0 +1,123 @@ +.collapsible-container { + display: flex; + justify-content: space-between; + align-items: flex-start; + margin: 20px 0; + } + + .collapsible-title { + font-weight: bold; + font-size: 1.25rem; + } + + .collapsible-button { + border: none; + background-color: transparent; + cursor: pointer; + padding: 0; + display: flex; + align-items: center; + + &:before { + content: '−'; + display: block; + font-size: 2rem; + color: #007bff; + margin-right: 10px; + } + + &.collapsed:before { + content: '+'; + } + } + + table { + width: 100%; + border-collapse: collapse; + margin-top: 1rem; + + th, + td { + text-align: left; + padding: 8px; + } + + th { + background-color: #f8f9fa; + } + + input[type='text'] { + width: 100%; + padding: 0.5rem; + margin-bottom: 0.5rem; + border: 1px solid #ced4da; + border-radius: 0.25rem; + } + + input[type='checkbox'] { + cursor: pointer; + } + } + + .group-select-container { + display: flex; + align-items: center; + + .group-select-label { + margin-right: 0.5rem; + } + + .group-select { + padding: 0.5rem; + margin-right: 1rem; + border: 1px solid #ced4da; + border-radius: 0.25rem; + } + + .max-group-text { + font-weight: bold; + } + } + + .variable-input-container { + margin-top: 1rem; + + label { + display: block; + margin-bottom: 0.5rem; + } + + input[type='text'] { + width: 100%; + padding: 0.5rem; + border: 1px solid #ced4da; + border-radius: 0.25rem; + margin-bottom: 1rem; + } + } + + .button-container { + display: flex; + justify-content: flex-end; + margin-top: 1rem; + + .button { + padding: 0.5rem 1rem; + border: none; + border-radius: 0.25rem; + cursor: pointer; + font-weight: bold; + margin-left: 0.5rem; + + &--save { + background-color: #28a745; + color: white; + } + + &--generate { + background-color: #007bff; + color: white; + } + } + } + \ No newline at end of file diff --git a/frontend/src/app/content/pages/documentpreview/GroupSelectionAndProvisions.tsx b/frontend/src/app/content/pages/documentpreview/GroupSelectionAndProvisions.tsx new file mode 100644 index 00000000..acba3237 --- /dev/null +++ b/frontend/src/app/content/pages/documentpreview/GroupSelectionAndProvisions.tsx @@ -0,0 +1,59 @@ +import React from 'react'; +import './GroupSelectionAndProvisions.scss'; + +interface Provision { + type: string; + provision: string; + freeText: string; + category: string; + included: boolean; +} + +interface GroupSelectionAndProvisionsProps { + selectedGroup: string; + setSelectedGroup: (value: string) => void; + provisions: Provision[]; + handleCheckboxChange: (index: number) => void; +} + +const GroupSelectionAndProvisions: React.FC = ({ + selectedGroup, + setSelectedGroup, + provisions, + handleCheckboxChange, +}) => { + return ( + <> +
+ + + + + + + + + + + + + + {provisions.map((item, index) => ( + + + + + + + + ))} + +
TypeProvisionFree TextCategoryIncluded
handleCheckboxChange(index)} />
+ + +
+ + ); +}; + +export default GroupSelectionAndProvisions; diff --git a/frontend/src/app/content/pages/documentpreview/InterestedPartiesDisplay.tsx b/frontend/src/app/content/pages/documentpreview/InterestedPartiesDisplay.tsx new file mode 100644 index 00000000..ca8b2bf9 --- /dev/null +++ b/frontend/src/app/content/pages/documentpreview/InterestedPartiesDisplay.tsx @@ -0,0 +1,50 @@ +import React from 'react'; + +interface Party { + clientName: string; + address: string; +} + +interface InterestedPartiesDisplayProps { + interestedParties: Party[]; +} +const customDivideString = (str: string): string[] => { + const words = str.split(' '); + if (words.length === 2) { + return [words[0], '', words[1]]; + } else if (words.length >= 3) { + return [words[0], words[1], words.slice(2).join(' ')]; + } + return words; +}; + + +const InterestedPartiesDisplay: React.FC = ({ interestedParties }) => { + + return ( +
+ {interestedParties.map((party, index) => ( +
+
+
First Name
+
{customDivideString(party.clientName)[0]}
+
+
+
Middle Name
+
{customDivideString(party.clientName)[1] || 'N/A'}
+
+
+
Last Name
+
{customDivideString(party.clientName)[2] || 'N/A'}
+
+
+
Address
+
{party.address}
+
+
+ ))} +
+ ); +}; + +export default InterestedPartiesDisplay; diff --git a/frontend/src/app/content/pages/documentpreview/LicenseDetailDisplay.tsx b/frontend/src/app/content/pages/documentpreview/LicenseDetailDisplay.tsx new file mode 100644 index 00000000..475a9c5c --- /dev/null +++ b/frontend/src/app/content/pages/documentpreview/LicenseDetailDisplay.tsx @@ -0,0 +1,48 @@ +import React from 'react'; + +interface LicenseDetailProps { + type: string; + subtype: string; + purpose: string; + subpurpose: string; + locationOfLand: string; + mailingAddress1: string; + mailingAddress2: string; + mailingAddress3: string; +} + +const LicenseDetailDisplay: React.FC = ({ + type, + subtype, + purpose, + subpurpose, + locationOfLand, + mailingAddress1, + mailingAddress2, + mailingAddress3 +}) => { + return ( +
+
+
Type
+
{type}
+
Subtype
+
{subtype}
+
Purpose
+
{purpose}
+
Subpurpose
+
{subpurpose}
+
Location of Land
+
{locationOfLand}
+
+
+
Primary Contact Address
+
{mailingAddress1}
+
{mailingAddress2}
+
{mailingAddress3}
+
+
+ ); +}; + +export default LicenseDetailDisplay; diff --git a/frontend/src/app/content/pages/documentpreview/ProvisionsTable.tsx b/frontend/src/app/content/pages/documentpreview/ProvisionsTable.tsx new file mode 100644 index 00000000..6ad868da --- /dev/null +++ b/frontend/src/app/content/pages/documentpreview/ProvisionsTable.tsx @@ -0,0 +1,72 @@ +import React from 'react'; + +interface Provision { + type: string; + provision: string; +} + +interface ProvisionsTableProps { + provisions: Provision[]; +} + +const ProvisionsTable: React.FC = ({ provisions }) => { + const handleInputChange = (index: number, field: keyof Provision, value: string) => { + const updatedProvisions = provisions.map((item, itemIndex) => + itemIndex === index ? { ...item, [field]: value } : item + ); + //setProvisions(updatedProvisions); + }; + + return ( + <> + + + + + + + + + {provisions.map((item, index) => ( + + + + + ))} + +
Document Variable NameEnter Text
+ handleInputChange(index, 'type', e.target.value)} + /> + + handleInputChange(index, 'provision', e.target.value)} + /> +
+
+ + {/* setVariableName(e.target.value) */ }} + /> +
+
+ + {/* setHelpText(e.target.value) */ }} + /> +
+ + + + ); +}; + +export default ProvisionsTable; diff --git a/frontend/src/app/types/types.ts b/frontend/src/app/types/types.ts index 0f0e1fc0..6b90058f 100644 --- a/frontend/src/app/types/types.ts +++ b/frontend/src/app/types/types.ts @@ -183,6 +183,7 @@ export type TemplateInfo = { active_flag: boolean; view: any; // remove from route remove: any; // remove from route + preview: any; // remove from route id: number; }; diff --git a/frontend/src/app/util/constants.ts b/frontend/src/app/util/constants.ts index 5f367a96..0c6fac31 100644 --- a/frontend/src/app/util/constants.ts +++ b/frontend/src/app/util/constants.ts @@ -39,6 +39,18 @@ export const PAGE = [ title: 'Manage Templates', path: 'manage-templates', }, + { + title: 'Document Preview', + path: '/' + }, + { + title: 'Select Manage Templates', + path: 'manage-templates-select' + }, + { + title: 'System Administration Menu', + path: 'system-admin-menu', + } ]; // should eventually be stored in a table in the db and obtained from there @@ -56,6 +68,8 @@ export const REPORT_TYPES = [ { reportIndex: 0, reportType: 'Land Use Report' }, { reportIndex: 1, reportType: 'Notice of Final Review' }, { reportIndex: 2, reportType: 'Grazing Lease' }, + { reportIndex: 3, reportType: 'Standard Licence' }, + { reportIndex: 4, reportType: 'Assignment Assumption' }, ]; export const CURRENT_REPORT_PAGES = { From def80b673c83e6d2d30b4441b5a1e0d66bbae2b4 Mon Sep 17 00:00:00 2001 From: mgtennant <100305096+mgtennant@users.noreply.github.com> Date: Thu, 14 Mar 2024 09:22:52 -0700 Subject: [PATCH 9/9] add report search function update --- backend/src/report/report.service.ts | 93 +++++++++++++--------------- 1 file changed, 43 insertions(+), 50 deletions(-) diff --git a/backend/src/report/report.service.ts b/backend/src/report/report.service.ts index a4c5b894..474ded67 100644 --- a/backend/src/report/report.service.ts +++ b/backend/src/report/report.service.ts @@ -787,59 +787,52 @@ export class ReportService { async getNFRData() { const nfrDataUrl = `${hostname}:${port}/nfr-data`; const templateUrl = `${hostname}:${port}/document-template/nfr-template-info`; - const nfrData = await axios - .get(nfrDataUrl) - .then((res) => { - return res.data; - }) - .catch((err) => console.log(err.response.data)); - const templateIds = []; - for (let entry of nfrData) { - templateIds.push(entry.template_id); + + // get NFR data + let nfrData; + try { + const response = await axios.get(nfrDataUrl); + nfrData = response.data; + } catch (err) { + console.log(err.response.data); + return; } - const allTemplates: { - id: number; - file_name: string; - active_flag: boolean; - is_deleted: boolean; - template_version: number; - }[] = await axios - .post(templateUrl, templateIds) - .then((res) => { - return res.data; - }) - .catch((err) => console.log(err.response.data)); - // Combine the corresponding templates with the nfr data. - const combinedArray = []; - - let i = 0; - let j = 0; - - while (i < allTemplates.length && j < nfrData.length) { - const template = allTemplates[i]; - const nfr = nfrData[j]; - - if (template.id === nfr.template_id) { - if (!template.is_deleted) { - combinedArray.push({ - dtid: nfr.dtid, - version: template.template_version, - file_name: template.file_name, - updated_date: nfr.update_timestamp.split('T')[0], - status: nfr.status, - active: template.active_flag, - nfr_id: nfr.id, - variant_name: nfr.variant_name, - }); - } - j++; - } else if (template.id < nfr.template_id) { - i++; - } else { - j++; - } + // get template IDs from NFR data + const templateIds = nfrData.map((entry) => entry.template_id); + + // get templates using template IDs + let allTemplates; + try { + const response = await axios.post(templateUrl, templateIds); + allTemplates = response.data; + } catch (err) { + console.log(err.response.data); + return; } + + // filter out deleted templates and create a lookup table + const templatesLookup = allTemplates.reduce((acc, template) => { + if (!template.is_deleted) { + acc[template.id] = template; + } + return acc; + }, {}); + + // combine NFR data with their corresponding templates + const combinedArray = nfrData + .filter((nfr) => templatesLookup[nfr.template_id]) + .map((nfr) => ({ + dtid: nfr.dtid, + version: templatesLookup[nfr.template_id].template_version, + file_name: templatesLookup[nfr.template_id].file_name, + updated_date: nfr.update_timestamp.split('T')[0], + status: nfr.status, + active: templatesLookup[nfr.template_id].active_flag, + nfr_id: nfr.id, + variant_name: nfr.variant_name, + })); + return combinedArray; }