Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add UEN field #2100

Merged
merged 6 commits into from
Jun 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/app/models/field/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import createSectionFieldSchema from './sectionField'
import createShortTextFieldSchema from './shortTextField'
import createStatementFieldSchema from './statementField'
import createTableFieldSchema from './tableField'
import createUenFieldSchema from './uenField'
import createYesNoFieldSchema from './yesNoField'

export {
Expand All @@ -38,6 +39,7 @@ export {
createShortTextFieldSchema,
createStatementFieldSchema,
createTableFieldSchema,
createUenFieldSchema,
createYesNoFieldSchema,
BaseFieldSchema,
}
7 changes: 7 additions & 0 deletions src/app/models/field/uenField.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Schema } from 'mongoose'

import { IUenFieldSchema } from '../../../types'

const createUenFieldSchema = () => new Schema<IUenFieldSchema>()

export default createUenFieldSchema
2 changes: 2 additions & 0 deletions src/app/models/form.server.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import {
createShortTextFieldSchema,
createStatementFieldSchema,
createTableFieldSchema,
createUenFieldSchema,
createYesNoFieldSchema,
} from './field'
import LogicSchema, {
Expand Down Expand Up @@ -405,6 +406,7 @@ const compileFormModel = (db: Mongoose): IFormModel => {
FormFieldPath.discriminator(BasicField.Image, createImageFieldSchema())
FormFieldPath.discriminator(BasicField.Date, createDateFieldSchema())
FormFieldPath.discriminator(BasicField.Nric, createNricFieldSchema())
FormFieldPath.discriminator(BasicField.Uen, createUenFieldSchema())
FormFieldPath.discriminator(BasicField.YesNo, createYesNoFieldSchema())
FormFieldPath.discriminator(
BasicField.Statement,
Expand Down
4 changes: 4 additions & 0 deletions src/app/utils/field-validation/answerValidator.factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
isSectionField,
isShortTextField,
isTableField,
isUenField,
isYesNoField,
} from '../../../types/field/utils/guards'
import { ResponseValidator } from '../../../types/field/utils/validation'
Expand All @@ -43,6 +44,7 @@ import { constructRatingValidator } from './validators/ratingValidator'
import { constructSectionValidator } from './validators/sectionValidator'
import { constructTableValidator } from './validators/tableValidator'
import constructTextValidator from './validators/textValidator'
import { constructUenValidator } from './validators/uenValidator'
import { constructYesNoValidator } from './validators/yesNoValidator'

/**
Expand Down Expand Up @@ -76,6 +78,8 @@ export const constructSingleAnswerValidator = (
return constructDropdownValidator(formField)
} else if (isEmailField(formField)) {
return constructEmailValidator(formField)
} else if (isUenField(formField)) {
return constructUenValidator()
} else if (isYesNoField(formField)) {
return constructYesNoValidator()
}
Expand Down
28 changes: 28 additions & 0 deletions src/app/utils/field-validation/validators/uenValidator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { chain, left, right } from 'fp-ts/lib/Either'
import { flow } from 'fp-ts/lib/function'

import { ProcessedSingleAnswerResponse } from 'src/app/modules/submission/submission.types'
import { ResponseValidator } from 'src/types/field/utils/validation'

import { isUenValid } from '../../../../shared/util/uen-validation'

import { notEmptySingleAnswerResponse } from './common'

type UenValidator = ResponseValidator<ProcessedSingleAnswerResponse>
type UenValidatorConstructor = () => UenValidator

/**
* Returns a validator to check if uen
* format is correct.
*/
const uenValidator: UenValidator = (response) => {
return isUenValid(response.answer)
? right(response)
: left(`UenValidator:\tanswer is not a valid UEN`)
}

/**
* Returns a validation function for a uen field when called.
*/
export const constructUenValidator: UenValidatorConstructor = () =>
flow(notEmptySingleAnswerResponse, chain(uenValidator))
6 changes: 6 additions & 0 deletions src/public/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ require('./modules/forms/base/components/field-number.client.component.js')
require('./modules/forms/base/components/field-rating.client.component.js')
require('./modules/forms/base/components/field-section.client.component.js')
require('./modules/forms/base/components/field-statement.client.component.js')
require('./modules/forms/base/components/field-uen.client.component.js')
require('./modules/forms/base/components/field-textarea.client.component.js')

// forms base directives
Expand All @@ -247,6 +248,7 @@ require('./modules/forms/base/directives/validate-checkbox.client.directive.js')
require('./modules/forms/base/directives/validate-email-domain.client.directive.js')
require('./modules/forms/base/directives/validate-email-format.client.directive.js')
require('./modules/forms/base/directives/validate-nric.client.directive.js')
require('./modules/forms/base/directives/validate-uen.client.directive.js')
require('./modules/forms/base/directives/validate-url.client.directive.js')
require('./modules/forms/base/directives/ng-intl-tel-input.js')
require('./modules/forms/base/directives/submit-form.directive.js')
Expand Down Expand Up @@ -606,6 +608,10 @@ app.run([
'modules/forms/base/componentViews/field-textarea.client.view.html',
require('./modules/forms/base/componentViews/field-textarea.client.view.html'),
)
$templateCache.put(
'modules/forms/base/componentViews/field-uen.client.view.html',
require('./modules/forms/base/componentViews/field-uen.client.view.html'),
)

// Forms base directiveViews
$templateCache.put(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<div class="text-field field-group row">
<!-- Question -->
<label
for="{{ vm.field._id || 'defaultID'}}"
class="field-question col-xs-12"
>
<div id="label-{{ vm.field._id || 'defaultID'}}">
<span class="field-number" ng-show="vm.field.field_number"
>{{ vm.field.field_number }}.</span
>
<span class="field-title">{{ vm.field.title }}</span>
<span class="field-optional" ng-if="!vm.field.required">(optional)</span>
</div>
<div
id="description-{{ vm.field._id || 'defaultID'}}"
class="field-description"
ng-if="vm.field.description"
ng-bind-html="vm.field.description | linky:'_blank'"
></div>
</label>

<!-- Input -->
<div class="col-xs-12 field-input">
<input
id="{{ vm.field._id || 'defaultID'}}"
type="text"
name="{{ vm.field._id || 'defaultID'}}"
class="input-custom input-large"
ng-model="vm.field.fieldValue"
ng-required="vm.field.required"
ng-disabled="vm.field.disabled"
ng-model-options="{ allowInvalid: true }"
ng-keyup="vm.forms.myForm[(vm.field._id || 'defaultID')].$setTouched()"
placeholder="Enter UEN"
autocomplete="off"
ng-trim="true"
ng-class="vm.field.disabled && vm.field.fieldValue ? 'myinfo-disable' : ''"
aria-labelledby="label-{{ vm.field._id || 'defaultID'}}"
aria-describedby="description-{{ vm.field._id || 'defaultID'}}"
validate-uen
/>
</div>

<!-- Error -->
<div
class="col-xs-12"
ng-show="vm.forms.myForm[(vm.field._id || 'defaultID')].$touched"
ng-messages="vm.forms.myForm[(vm.field._id || 'defaultID')].$error"
>
<field-error-component ng-message="required"></field-error-component>
<div ng-message="uenValidator" class="alert-custom alert-error">
<i class="bx bx-exclamation bx-md icon-spacing"></i>
<span class="alert-msg">Please enter a valid UEN</span>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
'use strict'

angular.module('forms').component('uenFieldComponent', {
templateUrl: 'modules/forms/base/componentViews/field-uen.client.view.html',
bindings: {
field: '<',
forms: '<',
},
controllerAs: 'vm',
})
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,6 @@
forms="forms"
>
</textarea-field-component>
<uen-field-component ng-switch-when="uen" field="field" forms="forms">
</uen-field-component>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
'use strict'

const { isUenValid } = require('../../../../../shared/util/uen-validation')

angular.module('forms').directive('validateUen', validateUen)

function validateUen() {
return {
restrict: 'A',
require: 'ngModel',
link: function (_scope, _elem, _attrs, ctrl) {
ctrl.$validators.uenValidator = function (modelValue) {
return ctrl.$isEmpty(modelValue) ? true : isUenValid(modelValue)
}
},
}
}
1 change: 1 addition & 0 deletions src/public/modules/forms/base/resources/icon-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const iconTypeMap = {
decimal: 'bx bx-calculator',
image: 'bx bx-image',
nric: 'bx bx-user',
uen: 'bx bx-building',
attachment: 'bx bx-cloud-download',
radiobutton: 'bx bx-radio-circle-marked',
table: 'bx bx-table',
Expand Down
1 change: 1 addition & 0 deletions src/public/modules/forms/helpers/field-factory.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ const getClass = (fieldType) => {
case 'textfield':
return TextField
case 'nric':
case 'uen':
case 'yes_no':
return SingleAnswerField
case 'image':
Expand Down
6 changes: 6 additions & 0 deletions src/shared/resources/basic/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@ export const types: IBasicFieldType[] = [
submitted: true,
answerArray: false,
},
{
name: BasicField.Uen,
value: 'UEN',
submitted: true,
answerArray: false,
},
{
name: BasicField.Table,
value: 'Table',
Expand Down
Loading