Skip to content

Commit

Permalink
DoB input should support "numbers of years" (#122)
Browse files Browse the repository at this point in the history
1.3.7
  • Loading branch information
freddieptf authored Apr 2, 2024
1 parent 08b6fc1 commit a1349b9
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 35 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cht-user-management",
"version": "1.3.6",
"version": "1.3.7",
"main": "dist/index.js",
"dependencies": {
"@fastify/autoload": "^5.8.0",
Expand Down
27 changes: 16 additions & 11 deletions src/lib/validator-dob.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,36 @@ import { DateTime } from 'luxon';
import { IValidator } from './validation';

export default class ValidatorDateOfBirth implements IValidator {
isValid(input: string) : boolean | string {
isValid(input: string) : boolean {
try {
const parsed = parse(input);
return parsed.isValid && parsed.diffNow('hours').hours <= 0;
const parsed = this.parse(input);
return parsed.isValid && parsed < DateTime.now();
} catch (e) {
return false;
}
}

format(input : string) : string {
const parsed = parse(input);
const parsed = this.parse(input);
const asISODate = parsed.toISODate();
if (!asISODate) {
if (!this.isValid(input) || !asISODate) {
return input;
}

return asISODate;
}

get defaultError(): string {
return 'Not a valid Date of Birth (eg. 1990-02-26)';
return 'Not a valid Date of Birth (eg. 1990-02-26 or 25)';
}
}

const parse = (input: string) => {
const strippedInput = input.replace(/ /ig, '');
return DateTime.fromISO(strippedInput);
};
private parse(input: string): DateTime {
const strippedInput = input.replace(/\s/ig, '');
const asNumber = Number(strippedInput);
if (!isNaN(asNumber) && asNumber > 0) {
return DateTime.now().minus({ years: asNumber });
}

return DateTime.fromISO(strippedInput);
}
}
21 changes: 21 additions & 0 deletions src/liquid/components/contact_type_dob.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<div class="control">
<input
name="{{ include.prop_name }}"
{% if include.isInYears %} type="text" {%else%} type="date" {%endif%}
class="input"
{% if data[include.prop_name] %} value="{{ data[include.prop_name] }}" {% endif %}
/>
</div>

<div class="field">
<div class="control">
<input
type="checkbox"
name="option_dob_unknown"
hx-target="#div_{{include.prefix}}{{include.prop.property_name}}"
hx-post="/place/dob?place_type={{include.place_type}}&prefix={{include.prefix}}&prop_type={{include.prop.type}}"
{% if include.isInYears %} checked {% endif%}
/>
<label>Date of birth unknown</label>
</div>
</div>
51 changes: 34 additions & 17 deletions src/liquid/components/contact_type_property.html
Original file line number Diff line number Diff line change
@@ -1,26 +1,43 @@
{% if include.prop.type != 'generated' %}
{% capture prop_name %}{{ include.prefix }}{{include.prop.property_name}}{% endcapture %}
<div class="field">

<div id="div_{{ include.prefix }}{{include.prop.property_name}}" class="field">
<label class="label">
{{include.prop.friendly_name}}
{% if data['option_dob_unknown'] %}
Age in Years
{%else%}
{{include.prop.friendly_name}}
{% endif%}
</label>
<div class="control">
{% if include.prop.type == 'select_one' or include.prop.type == 'select_multiple' %}
{%
include "components/contact_type_select.html"
{% if include.prop.type == 'dob' %}
{%
include "components/contact_type_dob.html"
prop_name=prop_name
isInYears=data['option_dob_unknown']
place_type=include.place_type
prefix=include.prefix
prop=include.prop
data=data
%}
{% else %}
<input
name="{{ prop_name }}"
type="{% if include.prop.type == 'dob' %}date{% else %}text{% endif %}"
class="input"
{% if false and include.prop.type == 'regex' %} pattern="{{ include.prop.parameter }}" {% endif %}
{% if data[prop_name] %} value="{{ data[prop_name] }}" {% endif %}
/>
{% endif %}
</div>
%}
{% else %}
<div class="control">
{% if include.prop.type == 'select_one' or include.prop.type == 'select_multiple' %}
{%
include "components/contact_type_select.html"
prop_name=prop_name
prop=include.prop
data=data
%}
{% else %}
<input
name="{{ prop_name }}"
type="{% if include.prop.type == 'dob' %}date{% else %}text{% endif %}"
class="input"
{% if false and include.prop.type == 'regex' %} pattern="{{ include.prop.parameter }}" {% endif %}
{% if data[prop_name] %} value="{{ data[prop_name] }}" {% endif %}
/>
{% endif %}
</div>
{% endif %}
</div>
{% endif %}
4 changes: 2 additions & 2 deletions src/liquid/place/create_form.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@

{% for prop in contactType.place_properties %}
{%
include "components/contact_type_property.html" prefix="place_" prop=prop
include "components/contact_type_property.html" prefix="place_" prop=prop place_type=contactType.name
%}
{% endfor %}
</section>
<section class="section is-small">
{% for prop in contactType.contact_properties %}
{%
include "components/contact_type_property.html" prefix="contact_" prop=prop
include "components/contact_type_property.html" prefix="contact_" prop=prop place_type=contactType.name
%}
{% endfor %}
</section>
Expand Down
13 changes: 13 additions & 0 deletions src/routes/add-place.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,19 @@ export default async function addPlace(fastify: FastifyInstance) {
return resp.view('src/liquid/app/view.html', tmplData);
});

fastify.post('/place/dob', async (req, resp) => {
const { place_type, prefix, prop_type } = req.query as any;
const contactType = Config.getContactType(place_type).contact_properties.find(prop => prop.type === prop_type);
return resp.view('src/liquid/components/contact_type_property.html', {
data: req.body,
include: {
prefix: prefix,
place_type: place_type,
prop: contactType
}
});
});

// you want to create a place? replace a contact? you'll have to go through me first
fastify.post('/place', async (req, resp) => {
const { op, type: placeType } = req.query as any;
Expand Down
9 changes: 7 additions & 2 deletions test/lib/validation.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { DateTime } from 'luxon';
import { expect } from 'chai';

import { Validation } from '../../src/lib/validation';
Expand Down Expand Up @@ -55,8 +56,12 @@ const scenarios: Scenario[] = [
{ type: 'dob', prop: '2030-05-25', isValid: false },
{ type: 'dob', prop: '2016-05-25', isValid: true, altered: '2016-05-25' },
{ type: 'dob', prop: ' 20 16- 05- 25 ', isValid: true, altered: '2016-05-25' },


{ type: 'dob', prop: '20', isValid: true, altered: DateTime.now().minus({ years: 20 }).toISODate() },
{ type: 'dob', prop: ' 20 ', isValid: true, altered: DateTime.now().minus({ years: 20 }).toISODate() },
{ type: 'dob', prop: 'abc', isValid: false, altered: 'abc' },
{ type: 'dob', prop: ' 1 0 0 ', isValid: true, altered: DateTime.now().minus({ years: 100 }).toISODate() },
{ type: 'dob', prop: '-1', isValid: false, altered: '-1' },

{ type: 'select_one', prop: ' male', isValid: true, propertyParameter: GENDER_OPTIONS },
{ type: 'select_one', prop: 'female ', isValid: true, propertyParameter: GENDER_OPTIONS },
{ type: 'select_one', prop: 'FeMale ', isValid: false, propertyParameter: GENDER_OPTIONS },
Expand Down

0 comments on commit a1349b9

Please sign in to comment.