Skip to content

Commit 32788ec

Browse files
ChiefStiefDana Stiefel
and
Dana Stiefel
authored
Feat/military affiliation (#426)
### Requirements List - A working LicenseeUser account ### Description List - Added in Military Status page - Added in Update Military Status page - Added in store + network modules needed to facilitate pages' functionality - Updated Licensee model and serializer to capture military affiliations api implementation - Added military affiliations model and serializer - Edited `FinalizePrivilegePurchase` page and `SelectedStatePurchaseInformation` component to refer to both the state and user's military status to make a military discount determination - Fixed bug in `InputRadioGroup` component causing multi-line labels to break layout - Added / updated tests as needed ### Testing List - `yarn test:unit:all` should run without errors or warnings - `yarn serve` should run without errors or warnings - `yarn build` should run without errors or warnings - Code review - On both mock and real api and in all screen sizes: 1) click on the view military status button to view your status page 2) Click edit info to go the doc upload page 3) Fill out the form, confirm it does not allow submission with no select choice and no / invalid document selection 4) Submit 5) View your updated military status (real api only) 6) Go through the privilege purchase flow and notice military affiliation discount is being applied 7) Return to the military status screen; try ending your military status 8) Status should now be inactive 9) Go back through privilege purchase flow, confirm military affiliation is no longer being applied Closes #281 Notes: - The real API system only saves one document upload submission per day. It will replace a prior submission in the day with your most recent one - The document upload is eventually consistent so your status may not immediately update. I've found it to take ~1 second but theoretically it could be longer. --------- Co-authored-by: Dana Stiefel <[email protected]>
1 parent 235c8ce commit 32788ec

39 files changed

+1790
-81
lines changed

webroot/src/components/Forms/InputFile/InputFile.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55
// Created by InspiringApps on 7/8/2020.
66
//
77

8-
import { Component, mixins, toNative } from 'vue-facing-decorator';
8+
import {
9+
Component,
10+
mixins,
11+
toNative
12+
} from 'vue-facing-decorator';
913
import { reactive } from 'vue';
1014
import MixinInput from '@components/Forms/_mixins/input.mixin';
1115
import UploadFileIcon from '@components/Icons/UploadFile/UploadFile.vue';

webroot/src/components/Forms/InputRadioGroup/InputRadioGroup.less

+5-2
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,14 @@
3939
label {
4040
display: flex;
4141
align-items: center;
42+
margin-left: 3rem;
4243
font-weight: @fontWeightLight;
4344
cursor: pointer;
4445

4546
&::before {
46-
display: inline-block;
47+
position: absolute;
48+
top: 0;
49+
left: -3rem;
4750
width: 2.0rem;
4851
height: 2.0rem;
4952
margin: 0 0.3rem 0 0;
@@ -60,7 +63,7 @@
6063
input[type='radio']:checked + label::after {
6164
position: absolute;
6265
top: 0.4rem;
63-
left: 0.4rem;
66+
left: -2.6rem;
6467
display: block;
6568
width: 1.4rem;
6669
height: 1.4rem;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//
2+
// MilitaryDocumentRow.less
3+
// InspiringApps modules
4+
//
5+
// Created by InspiringApps on 4/30/2021.
6+
//
7+
8+
.example-row {
9+
display: flex;
10+
flex-direction: column;
11+
padding: 0.8rem 0;
12+
border-bottom: 0.1rem solid @midGrey;
13+
14+
@media @tabletWidth {
15+
flex-direction: row;
16+
}
17+
18+
.cell {
19+
flex-basis: 0;
20+
flex-grow: 1;
21+
flex-shrink: 1;
22+
color: @veryDarkGrey;
23+
24+
&.is-header {
25+
display: none;
26+
font-weight: @fontWeightBold;
27+
28+
@media @tabletWidth {
29+
display: flex;
30+
}
31+
}
32+
33+
.cell-title {
34+
font-weight: @fontWeightBold;
35+
}
36+
}
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//
2+
// MilitaryDocumentRow.spec.ts
3+
// InspiringApps modules
4+
//
5+
// Created by InspiringApps on 4/30/2021.
6+
//
7+
8+
import { expect } from 'chai';
9+
import { mountShallow } from '@tests/helpers/setup';
10+
import MilitaryDocumentRow from '@components/MilitaryDocumentRow/MilitaryDocumentRow.vue';
11+
12+
describe('MilitaryDocumentRow component', async () => {
13+
it('should mount the component', async () => {
14+
const wrapper = await mountShallow(MilitaryDocumentRow, {
15+
props: {
16+
item: {},
17+
}
18+
});
19+
20+
expect(wrapper.exists()).to.equal(true);
21+
expect(wrapper.findComponent(MilitaryDocumentRow).exists()).to.equal(true);
22+
});
23+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//
2+
// MilitaryDocumentRow.ts
3+
// InspiringApps modules
4+
//
5+
// Created by InspiringApps on 4/30/2021.
6+
//
7+
8+
import { Component, Prop, Vue } from 'vue-facing-decorator';
9+
10+
@Component
11+
export default class MilitaryDocumentRow extends Vue {
12+
@Prop({ required: true }) item!: any;
13+
@Prop({ default: false }) isHeaderRow?: boolean;
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<!--
2+
MilitaryDocumentRow.vue
3+
InspiringApps modules
4+
5+
Created by InspiringApps on 4/30/2021.
6+
-->
7+
8+
<template>
9+
<li class="example-row">
10+
<div class="cell" :class="{ 'is-header': isHeaderRow }">
11+
<span v-if="$matches.phone.only" class="cell-title">{{ $t('military.fileName') }}:</span>
12+
{{ item.name }}
13+
</div>
14+
<div class="cell" :class="{ 'is-header': isHeaderRow }">
15+
<span v-if="$matches.phone.only" class="cell-title">{{ $t('military.dateUploaded') }}:</span>
16+
{{ item.date }}
17+
</div>
18+
</li>
19+
</template>
20+
21+
<script lang="ts" src="./MilitaryDocumentRow.ts"></script>
22+
<style scoped lang="less" src="./MilitaryDocumentRow.less"></style>

webroot/src/components/SelectedStatePurchaseInformation/SelectedStatePurchaseInformation.less

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
height: 4rem;
6565
margin: -1rem -1.2rem 0 0;
6666
padding: 0;
67-
color: white;
67+
color: @white;
6868

6969
@media @tabletWidth {
7070
margin: 0 -1.2rem 0 0;

webroot/src/components/SelectedStatePurchaseInformation/SelectedStatePurchaseInformation.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ class SelectedStatePurchaseInformation extends mixins(MixinForm) {
110110
}
111111

112112
get militaryDiscountText(): string {
113-
return this.$t('licensing.militaryDiscountText');
113+
return this.$t('military.militaryDiscountText');
114114
}
115115

116116
get jurisprudenceModalTitle(): string {
@@ -149,8 +149,12 @@ class SelectedStatePurchaseInformation extends mixins(MixinForm) {
149149
return this.selectedStatePurchaseData?.isMilitaryDiscountActive || false;
150150
}
151151

152+
get shouldApplyMilitaryDiscount(): boolean {
153+
return Boolean(this.isMilitaryDiscountActive && this.licensee?.isMilitary());
154+
}
155+
152156
get subTotal(): string {
153-
const militaryDiscount = this.isMilitaryDiscountActive
157+
const militaryDiscount = this.shouldApplyMilitaryDiscount
154158
&& this.selectedStatePurchaseData?.militaryDiscountAmount
155159
? this.selectedStatePurchaseData?.militaryDiscountAmount : 0;
156160

webroot/src/components/SelectedStatePurchaseInformation/SelectedStatePurchaseInformation.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
<div class="info-row-label">{{commissionFeeText}}</div>
3131
<div class="expire-date-value">${{currentCompactCommissionFeeDisplay}}</div>
3232
</div>
33-
<div v-if="selectedStatePurchaseData.isMilitaryDiscountActive" class="info-row sub-row">
33+
<div v-if="shouldApplyMilitaryDiscount" class="info-row sub-row">
3434
<div class="info-row-label">{{militaryDiscountText}}</div>
3535
<div class="expire-date-value">-${{militaryDiscountAmountDisplay}}</div>
3636
</div>

webroot/src/locales/en.json

+37-1
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,7 @@
477477
"licensing": {
478478
"license": "License",
479479
"licensingListTitle": "Licensing Data",
480+
"attestation": "Attestation",
480481
"searchTitle": "Begin a search",
481482
"searchSubtext": "Enter at least one field to search for licensing data.",
482483
"licenseExpiredMessage": "Your license has expired.",
@@ -498,7 +499,6 @@
498499
"state": "State",
499500
"issued": "Issued",
500501
"expirationDate": "Expiration date",
501-
"militaryDiscountText": "Military Discount",
502502
"expireDate": "Expire Date",
503503
"expires": "Expires",
504504
"selectPrivileges": "Select privileges",
@@ -553,6 +553,42 @@
553553
}
554554
]
555555
},
556+
"military": {
557+
"militaryStatusTitle": "Military status",
558+
"updateMilitaryStatusTitle": "Update military status",
559+
"viewMilitaryStatus": "View military status",
560+
"militaryDiscountText": "Military Discount",
561+
"affiliationType": "Affiliation Type",
562+
"previouslyUploadedDocuments": "Previously Uploaded Documents",
563+
"endMilitaryAffiliation": "End military affiliation",
564+
"editInfo": "Edit info",
565+
"noUploadedDocuments": "No uploaded documents",
566+
"endAffiliationModalTitle": "Are you sure you want to end your military affiliation?",
567+
"endAffiliationModalContent" : "This action cannot be undone, but if needed, you can go through the confirmation process again.",
568+
"noGoBack": "No, go back",
569+
"yesEnd": "Yes, end my affiliation",
570+
"affiliationAttestationOptions": [
571+
{
572+
"name": "I hereby attest and affirm that I am an active-duty military member, defined as a person with a full-time duty status in the active uniformed service of the United States, including members of the National Guard and Reserve on active duty orders.",
573+
"value": "militaryMember"
574+
},
575+
{
576+
"name": "I hereby attest and affirm that I am the legal spouse of an active-duty military member, defined as a person with a full-time duty status in the active uniformed service of the United States, including members of the National Guard and Reserve on active duty orders.",
577+
"value": "militaryMemberSpouse"
578+
}
579+
],
580+
"affiliationTypes": {
581+
"militaryMember": "Active-duty military member",
582+
"militaryMemberSpouse": "Active-duty military spouse",
583+
"none": "N/A"
584+
},
585+
"documentProofLabel": "Upload proof of military affiliation*",
586+
"successLongProcess": "Submit successful, your status may take a minute to process",
587+
"submitFail": "Error uploading document",
588+
"fileInstructions": "Only 1 file (PDF, docx, png, jpeg only)",
589+
"fileName": "File name",
590+
"dateUploaded": "Date uploaded"
591+
},
556592
"account": {
557593
"accountTitle": "Account",
558594
"usersListTitle": "Users",

webroot/src/locales/es.json

+37-1
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,7 @@
477477
"licensing": {
478478
"licensingListTitle": "Datos de licencia",
479479
"searchTitle": "Iniciar una búsqueda",
480+
"attestation": "Atestación",
480481
"searchSubtext": "Introduzca al menos un campo para buscar datos de licencia.",
481482
"searchLabel": "Buscar",
482483
"searchPlaceholderName": "Introducir nombre",
@@ -491,7 +492,6 @@
491492
"issueDate": "Fecha de asunto",
492493
"expireDate": "Fecha de caducidad",
493494
"expirationDate": "Fecha de caducidad",
494-
"militaryDiscountText": "Descuento Militar",
495495
"lastUpdate": "Última carga",
496496
"license": "Licencia",
497497
"licenseExpiredMessage": "Su licencia ha caducado.",
@@ -553,6 +553,42 @@
553553
}
554554
]
555555
},
556+
"military": {
557+
"militaryStatusTitle": "Estado militar",
558+
"updateMilitaryStatusTitle": "Actualizar el estado militar",
559+
"militaryDiscountText": "Descuento Militar",
560+
"viewMilitaryStatus": "Ver estado militar",
561+
"affiliationType": "Tipo de afiliación",
562+
"previouslyUploadedDocuments": "Previously Uploaded Documents",
563+
"endMilitaryAffiliation": "Parar afiliación militar",
564+
"editInfo": "Editar información",
565+
"noUploadedDocuments": "No documentos cargados",
566+
"endAffiliationModalTitle": "¿Está seguro de que desea poner fin a su afiliación militar?",
567+
"endAffiliationModalContent" : "Esta acción no se puede deshacer, pero si es necesario, puedes volver a realizar el proceso de confirmación.",
568+
"noGoBack": "No, regresa",
569+
"yesEnd": "Sí, terminar mi afiliación",
570+
"affiliationAttestationOptions": [
571+
{
572+
"name": "Por la presente doy fe y afirmo que soy un miembro militar en servicio activo, definido como una persona con un estado de servicio de tiempo completo en el servicio uniformado activo de los Estados Unidos, incluidos los miembros de la Guardia Nacional y la Reserva en servicio activo.",
573+
"value": "militaryMember"
574+
},
575+
{
576+
"name": "Por la presente doy fe y afirmo que soy el cónyuge legal de un miembro militar en servicio activo, definido como una persona con estatus de servicio de tiempo completo en el servicio uniformado activo de los Estados Unidos, incluidos los miembros de la Guardia Nacional y la Reserva en activo. órdenes de servicio.",
577+
"value": "militaryMemberSpouse"
578+
}
579+
],
580+
"affiliationTypes": {
581+
"militaryMember": "Miembro militar en servicio activo",
582+
"militaryMemberSpouse": "Esposo militar en servicio activo",
583+
"none": "N/A"
584+
},
585+
"documentProofLabel": "Cargar prueba de afiliación militar",
586+
"successLongProcess": "Enviado correctamente, su estado puede tardar un minuto en procesarse",
587+
"submitFail": "Error al cargar el documento",
588+
"fileInstructions": "Sólo 1 archivo (sólo PDF, docx, png, jpeg)",
589+
"fileName": "Nombre del archivo",
590+
"dateUploaded": "Fecha de carga"
591+
},
556592
"account": {
557593
"accountTitle": "Cuenta",
558594
"usersListTitle": "Usuarios",

0 commit comments

Comments
 (0)