Skip to content

Commit

Permalink
feat: refactor view application route (#34)
Browse files Browse the repository at this point in the history
* feat: refactor view application route

* fix: linting

* feat: refactor applications route

* feat: refactor applications route

* skip: sonar codesmell

* fix: missing filter
  • Loading branch information
shivanshuit914 authored Aug 17, 2022
1 parent 3afcbba commit db8e9f5
Show file tree
Hide file tree
Showing 13 changed files with 279 additions and 244 deletions.
31 changes: 31 additions & 0 deletions app/lib/search-validation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const appRefRegEx = /^vv-[\da-f]{4}-[\da-f]{4}$/i
const validStatus = ['applied', 'withdrawn', 'data inputted', 'claimed', 'check', 'accepted', 'rejected', 'paid']
const sbiRegEx = /^[\0-9]{9}$/i

module.exports = (searchText) => {
let searchType
searchText = (searchText ?? '').trim()
switch (true) {
case appRefRegEx.test(searchText):
searchType = 'ref'
break
case validStatus.indexOf(searchText.toLowerCase()) !== -1:
searchType = 'status'
break
case sbiRegEx.test(searchText):
searchType = 'sbi'
break
}

if (!searchType && searchText.length <= 0) {
searchType = 'reset'
}
if (searchType) {
return {
searchText,
searchType
}
} else {
throw new Error('Invalid search. It should be application reference or status or sbi number.')
}
}
122 changes: 7 additions & 115 deletions app/routes/applications.js
Original file line number Diff line number Diff line change
@@ -1,121 +1,13 @@
const viewTemplate = 'applications'
const currentPath = `/${viewTemplate}`
const { getApplications } = require('../api/applications')
const { getPagination, getPagingData, displayPageSize } = require('../pagination')
const { displayPageSize } = require('../pagination')
const Joi = require('joi')
const { setAppSearch, getAppSearch } = require('../session')
const keys = require('../session/keys')
const getStyleClassByStatus = require('../constants/status')
const { administrator, processor, user } = require('../auth/permissions')
async function createModel (request, page) {
page = page ?? request.query.page ?? 1
const { limit, offset } = getPagination(page)
const path = request.headers.path ?? ''
const searchText = getAppSearch(request, keys.appSearch.searchText)
const searchType = getAppSearch(request, keys.appSearch.searchType)
const filterStatus = getAppSearch(request, keys.appSearch.filterStatus) ?? []
const apps = await getApplications(searchType, searchText, limit, offset, filterStatus)
if (apps.total > 0) {
let statusClass
const applications = apps.applications.map(n => {
statusClass = getStyleClassByStatus(n.status.status)
return [
{ text: n.reference },
{ text: n.data?.organisation?.name },
{
text: n.data?.organisation?.sbi,
format: 'numeric',
attributes: {
'data-sort-value': n.data?.organisation?.sbi
}
},
{
text: new Date(n.createdAt).toLocaleDateString('en-GB'),
format: 'date',
attributes: {
'data-sort-value': n.createdAt
}
},
{
html: `<span class="govuk-tag ${statusClass}">${n.status.status}</span>`,
attributes: {
'data-sort-value': `${n.status.status}`
}
},
{ html: `<a href="view-application/${n.reference}">View application</a>` }
]
})
const pagingData = getPagingData(apps.total ?? 0, limit, page, path)
const groupByStatus = apps.applicationStatus.map(s => {
return {
status: s.status,
total: s.total,
styleClass: getStyleClassByStatus(s.status),
selected: filterStatus.filter(f => f === s.status).length > 0
}
})
return {
applications,
...pagingData,
searchText,
availableStatus: groupByStatus,
selectedStatus: groupByStatus.filter(s => s.selected === true).map(s => {
return {
href: `${currentPath}/remove/${s.status}`,
classes: s.styleClass,
text: s.status
}
}),
filterStatus: groupByStatus.map(s => {
return {
value: s.status,
html: `<div class="govuk-tag ${s.styleClass}" style="color:#104189;" >${s.status} (${s.total}) </div>`,
checked: s.selected,
styleClass: s.styleClass
}
})
}
} else {
return {
applications: [],
error: 'No Applications found.',
searchText,
availableStatus: [],
selectedStatus: [],
filterStatus: []
}
}
}
const appRefRegEx = /^vv-[\da-f]{4}-[\da-f]{4}$/i
const validStatus = ['applied', 'withdrawn', 'data inputted', 'claimed', 'check', 'accepted', 'rejected', 'paid']
const sbiRegEx = /^[\0-9]{9}$/i
function checkValidSearch (searchText) {
let searchType
searchText = (searchText ?? '').trim()
switch (true) {
case appRefRegEx.test(searchText):
searchType = 'ref'
break
case validStatus.indexOf(searchText.toLowerCase()) !== -1:
searchType = 'status'
break
case sbiRegEx.test(searchText):
searchType = 'sbi'
break
}
const ViewModel = require('./models/application-list')
const checkValidSearch = require('../lib/search-validation')

if (!searchType && searchText.length <= 0) {
searchType = 'reset'
}
if (searchType) {
return {
searchText,
searchType
}
} else {
throw new Error('Invalid search. It should be application reference or status or sbi number.')
}
}
module.exports = [
{
method: 'GET',
Expand All @@ -129,7 +21,7 @@ module.exports = [
})
},
handler: async (request, h) => {
return h.view(viewTemplate, await createModel(request))
return h.view(viewTemplate, await new ViewModel(request)) // NOSONAR
}
}
},
Expand All @@ -140,7 +32,7 @@ module.exports = [
auth: { scope: [administrator, processor, user] },
handler: async (request, h) => {
setAppSearch(request, keys.appSearch.filterStatus, [])
return h.view(viewTemplate, await createModel(request))
return h.view(viewTemplate, await new ViewModel(request)) // NOSONAR
}
}
},
Expand All @@ -158,7 +50,7 @@ module.exports = [
let filterStatus = getAppSearch(request, keys.appSearch.filterStatus)
filterStatus = filterStatus.filter(s => s !== request.params.status)
setAppSearch(request, keys.appSearch.filterStatus, filterStatus)
return h.view(viewTemplate, await createModel(request))
return h.view(viewTemplate, await new ViewModel(request)) // NOSONAR
}
}
},
Expand Down Expand Up @@ -186,7 +78,7 @@ module.exports = [
const { searchText, searchType } = checkValidSearch(request.payload.searchText)
setAppSearch(request, keys.appSearch.searchText, searchText ?? '')
setAppSearch(request, keys.appSearch.searchType, searchType ?? '')
return h.view(viewTemplate, await createModel(request, 1))
return h.view(viewTemplate, await new ViewModel(request, 1)) // NOSONAR
} catch (err) {
return h.view(viewTemplate, { ...request.payload, error: err }).code(400).takeover()
}
Expand Down
11 changes: 11 additions & 0 deletions app/routes/models/application-claim.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const { formatedDateToUk } = require('../../lib/display-helper')

module.exports = (updatedAt) => {
const formatedDate = formatedDateToUk(updatedAt)
return {
head: [{ text: 'Date' }, { text: 'Data requested' }, { text: 'Data entered' }],
rows: [
[{ text: formatedDate }, { text: 'Details correct?' }, { text: 'Yes' }]
]
}
}
98 changes: 98 additions & 0 deletions app/routes/models/application-list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
const { getApplications } = require('../../api/applications')
const { getPagination, getPagingData } = require('../../pagination')
const { getAppSearch } = require('../../session')
const getStyleClassByStatus = require('../../constants/status')
const keys = require('../../session/keys')

class ViewModel {
constructor (request, page) {
return (async () => {
this.model = await createModel(request, page)
return this
})()
}
}

async function createModel (request, page) {
const viewTemplate = 'applications'
const currentPath = `/${viewTemplate}`
page = page ?? request.query.page ?? 1
const { limit, offset } = getPagination(page)
const path = request.headers.path ?? ''
const searchText = getAppSearch(request, keys.appSearch.searchText)
const searchType = getAppSearch(request, keys.appSearch.searchType)
const filterStatus = getAppSearch(request, keys.appSearch.filterStatus) ?? []
const apps = await getApplications(searchType, searchText, limit, offset, filterStatus)
if (apps.total > 0) {
let statusClass
const applications = apps.applications.map(n => {
statusClass = getStyleClassByStatus(n.status.status)
return [
{ text: n.reference },
{ text: n.data?.organisation?.name },
{
text: n.data?.organisation?.sbi,
format: 'numeric',
attributes: {
'data-sort-value': n.data?.organisation?.sbi
}
},
{
text: new Date(n.createdAt).toLocaleDateString('en-GB'),
format: 'date',
attributes: {
'data-sort-value': n.createdAt
}
},
{
html: `<span class="govuk-tag ${statusClass}">${n.status.status}</span>`,
attributes: {
'data-sort-value': `${n.status.status}`
}
},
{ html: `<a href="view-application/${n.reference}">View application</a>` }
]
})
const pagingData = getPagingData(apps.total ?? 0, limit, page, path)
const groupByStatus = apps.applicationStatus.map(s => {
return {
status: s.status,
total: s.total,
styleClass: getStyleClassByStatus(s.status),
selected: filterStatus.filter(f => f === s.status).length > 0
}
})
return {
applications,
...pagingData,
searchText,
availableStatus: groupByStatus,
selectedStatus: groupByStatus.filter(s => s.selected === true).map(s => {
return {
href: `${currentPath}/remove/${s.status}`,
classes: s.styleClass,
text: s.status
}
}),
filterStatus: groupByStatus.map(s => {
return {
value: s.status,
html: `<div class="govuk-tag ${s.styleClass}" style="color:#104189;" >${s.status} (${s.total}) </div>`,
checked: s.selected,
styleClass: s.styleClass
}
})
}
} else {
return {
applications: [],
error: 'No Applications found.',
searchText,
availableStatus: [],
selectedStatus: [],
filterStatus: []
}
}
}

module.exports = ViewModel
7 changes: 7 additions & 0 deletions app/routes/models/application-organisation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = (organisation) => {
return [
{ key: { text: 'SBI number:' }, value: { text: organisation?.sbi } },
{ key: { text: 'Address:' }, value: { text: organisation?.address } },
{ key: { text: 'Email address:' }, value: { text: organisation?.email } }
]
}
23 changes: 23 additions & 0 deletions app/routes/models/application-payment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const { formatedDateToUk } = require('../../lib/display-helper')

module.exports = (payment) => {
const { data, createdAt } = payment
const formatedDate = formatedDateToUk(createdAt)
const rows = []
data.invoiceLines.forEach(invoiceLine => {
rows.push([{ text: formatedDate }, { text: invoiceLine.description }, { text: ${data?.value?.toFixed(2)}` }])
})

if (data.frn) {
rows.push([{ text: formatedDate }, { text: 'FRN number' }, { text: data.frn }])
}

if (data.invoiceNumber) {
rows.push([{ text: formatedDate }, { text: 'Invoice number' }, { text: data.invoiceNumber }])
}

return {
head: [{ text: 'Date' }, { text: 'Data requested' }, { text: 'Data entered' }],
rows
}
}
16 changes: 16 additions & 0 deletions app/routes/models/farmer-application.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const { formatedDateToUk, upperFirstLetter } = require('../../lib/display-helper')
const speciesNumbers = require('../../../app/constants/species-numbers')

module.exports = (application) => {
const { data, createdAt } = application
const formatedDate = formatedDateToUk(createdAt)
return {
head: [{ text: 'Date' }, { text: 'Data requested' }, { text: 'Data entered' }],
rows: [
[{ text: formatedDate }, { text: 'Detail correct?' }, { text: upperFirstLetter(data.confirmCheckDetails) }],
[{ text: formatedDate }, { text: 'Review type' }, { text: upperFirstLetter(data.whichReview) }],
[{ text: formatedDate }, { text: 'Livestock number' }, { text: speciesNumbers[data.whichReview] }],
[{ text: formatedDate }, { text: 'T&Cs agreed?' }, { text: data.declaration ? 'Yes' : 'No' }]
]
}
}
Loading

0 comments on commit db8e9f5

Please sign in to comment.