diff --git a/.circleci/config.yml b/.circleci/config.yml index e5da89d6f0d..a79d55dcf3f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -259,7 +259,7 @@ executors: commands: create_dot_go_version: - description: "Creates a .go-version file (if needed) which can be used for cache keys specific to golang" + description: 'Creates a .go-version file (if needed) which can be used for cache keys specific to golang' steps: - run: name: Create a .go-version file @@ -1237,7 +1237,7 @@ jobs: # # The trailing hyphen in restore_cache seems important # according to the page linked above - - v6-spectral-lint- + - v7-spectral-lint- - run: name: Save Baseline Spectral Lint command: | @@ -1296,7 +1296,7 @@ jobs: # Use the BuildNum to update the cache key so that the # coverage cache is always updated - save_cache: - key: v6-spectral-lint-{{ .BuildNum }} + key: v7-spectral-lint-{{ .BuildNum }} paths: - ~/transcom/mymove/spectral - store_artifacts: diff --git a/pkg/gen/internalapi/embedded_spec.go b/pkg/gen/internalapi/embedded_spec.go index be339cd9c02..f13223db818 100644 --- a/pkg/gen/internalapi/embedded_spec.go +++ b/pkg/gen/internalapi/embedded_spec.go @@ -4160,6 +4160,9 @@ func init() { "department_indicator": { "$ref": "#/definitions/DeptIndicator" }, + "grade": { + "$ref": "#/definitions/OrderPayGrade" + }, "has_dependents": { "type": "boolean", "title": "Are dependents included in your orders?" @@ -4188,6 +4191,11 @@ func init() { "orders_type_detail": { "$ref": "#/definitions/OrdersTypeDetail" }, + "origin_duty_location_id": { + "type": "string", + "format": "uuid", + "example": "c56a4180-65aa-42ec-a945-5fd21dec0538" + }, "report_by_date": { "description": "Report By Date", "type": "string", @@ -5548,6 +5556,73 @@ func init() { "x-nullable": true, "x-omitempty": false }, + "OrderPayGrade": { + "type": "string", + "title": "Rank", + "enum": [ + "E_1", + "E_2", + "E_3", + "E_4", + "E_5", + "E_6", + "E_7", + "E_8", + "E_9", + "E_9_SPECIAL_SENIOR_ENLISTED", + "O_1_ACADEMY_GRADUATE", + "O_2", + "O_3", + "O_4", + "O_5", + "O_6", + "O_7", + "O_8", + "O_9", + "O_10", + "W_1", + "W_2", + "W_3", + "W_4", + "W_5", + "AVIATION_CADET", + "CIVILIAN_EMPLOYEE", + "ACADEMY_CADET", + "MIDSHIPMAN" + ], + "x-display-value": { + "ACADEMY_CADET": "Service Academy Cadet", + "AVIATION_CADET": "Aviation Cadet", + "CIVILIAN_EMPLOYEE": "Civilian Employee", + "E_1": "E-1", + "E_2": "E-2", + "E_3": "E-3", + "E_4": "E-4", + "E_5": "E-5", + "E_6": "E-6", + "E_7": "E-7", + "E_8": "E-8", + "E_9": "E-9", + "E_9_SPECIAL_SENIOR_ENLISTED": "E-9 (Special Senior Enlisted)", + "MIDSHIPMAN": "Midshipman", + "O_10": "O-10", + "O_1_ACADEMY_GRADUATE": "O-1 or Service Academy Graduate", + "O_2": "O-2", + "O_3": "O-3", + "O_4": "O-4", + "O_5": "O-5", + "O_6": "O-6", + "O_7": "O-7", + "O_8": "O-8", + "O_9": "O-9", + "W_1": "W-1", + "W_2": "W-2", + "W_3": "W-3", + "W_4": "W-4", + "W_5": "W-5" + }, + "x-nullable": true + }, "Orders": { "type": "object", "required": [ @@ -12741,6 +12816,9 @@ func init() { "department_indicator": { "$ref": "#/definitions/DeptIndicator" }, + "grade": { + "$ref": "#/definitions/OrderPayGrade" + }, "has_dependents": { "type": "boolean", "title": "Are dependents included in your orders?" @@ -12769,6 +12847,11 @@ func init() { "orders_type_detail": { "$ref": "#/definitions/OrdersTypeDetail" }, + "origin_duty_location_id": { + "type": "string", + "format": "uuid", + "example": "c56a4180-65aa-42ec-a945-5fd21dec0538" + }, "report_by_date": { "description": "Report By Date", "type": "string", @@ -14133,6 +14216,73 @@ func init() { "x-nullable": true, "x-omitempty": false }, + "OrderPayGrade": { + "type": "string", + "title": "Rank", + "enum": [ + "E_1", + "E_2", + "E_3", + "E_4", + "E_5", + "E_6", + "E_7", + "E_8", + "E_9", + "E_9_SPECIAL_SENIOR_ENLISTED", + "O_1_ACADEMY_GRADUATE", + "O_2", + "O_3", + "O_4", + "O_5", + "O_6", + "O_7", + "O_8", + "O_9", + "O_10", + "W_1", + "W_2", + "W_3", + "W_4", + "W_5", + "AVIATION_CADET", + "CIVILIAN_EMPLOYEE", + "ACADEMY_CADET", + "MIDSHIPMAN" + ], + "x-display-value": { + "ACADEMY_CADET": "Service Academy Cadet", + "AVIATION_CADET": "Aviation Cadet", + "CIVILIAN_EMPLOYEE": "Civilian Employee", + "E_1": "E-1", + "E_2": "E-2", + "E_3": "E-3", + "E_4": "E-4", + "E_5": "E-5", + "E_6": "E-6", + "E_7": "E-7", + "E_8": "E-8", + "E_9": "E-9", + "E_9_SPECIAL_SENIOR_ENLISTED": "E-9 (Special Senior Enlisted)", + "MIDSHIPMAN": "Midshipman", + "O_10": "O-10", + "O_1_ACADEMY_GRADUATE": "O-1 or Service Academy Graduate", + "O_2": "O-2", + "O_3": "O-3", + "O_4": "O-4", + "O_5": "O-5", + "O_6": "O-6", + "O_7": "O-7", + "O_8": "O-8", + "O_9": "O-9", + "W_1": "W-1", + "W_2": "W-2", + "W_3": "W-3", + "W_4": "W-4", + "W_5": "W-5" + }, + "x-nullable": true + }, "Orders": { "type": "object", "required": [ diff --git a/pkg/gen/internalmessages/create_update_orders.go b/pkg/gen/internalmessages/create_update_orders.go index dec96caa98b..2eeba1bfa95 100644 --- a/pkg/gen/internalmessages/create_update_orders.go +++ b/pkg/gen/internalmessages/create_update_orders.go @@ -22,6 +22,9 @@ type CreateUpdateOrders struct { // department indicator DepartmentIndicator *DeptIndicator `json:"department_indicator,omitempty"` + // grade + Grade *OrderPayGrade `json:"grade,omitempty"` + // Are dependents included in your orders? // Required: true HasDependents *bool `json:"has_dependents"` @@ -51,6 +54,11 @@ type CreateUpdateOrders struct { // orders type detail OrdersTypeDetail *OrdersTypeDetail `json:"orders_type_detail,omitempty"` + // origin duty location id + // Example: c56a4180-65aa-42ec-a945-5fd21dec0538 + // Format: uuid + OriginDutyLocationID strfmt.UUID `json:"origin_duty_location_id,omitempty"` + // Report-by date // // Report By Date @@ -86,6 +94,10 @@ func (m *CreateUpdateOrders) Validate(formats strfmt.Registry) error { res = append(res, err) } + if err := m.validateGrade(formats); err != nil { + res = append(res, err) + } + if err := m.validateHasDependents(formats); err != nil { res = append(res, err) } @@ -106,6 +118,10 @@ func (m *CreateUpdateOrders) Validate(formats strfmt.Registry) error { res = append(res, err) } + if err := m.validateOriginDutyLocationID(formats); err != nil { + res = append(res, err) + } + if err := m.validateReportByDate(formats); err != nil { res = append(res, err) } @@ -143,6 +159,25 @@ func (m *CreateUpdateOrders) validateDepartmentIndicator(formats strfmt.Registry return nil } +func (m *CreateUpdateOrders) validateGrade(formats strfmt.Registry) error { + if swag.IsZero(m.Grade) { // not required + return nil + } + + if m.Grade != nil { + if err := m.Grade.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("grade") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("grade") + } + return err + } + } + + return nil +} + func (m *CreateUpdateOrders) validateHasDependents(formats strfmt.Registry) error { if err := validate.Required("has_dependents", "body", m.HasDependents); err != nil { @@ -221,6 +256,18 @@ func (m *CreateUpdateOrders) validateOrdersTypeDetail(formats strfmt.Registry) e return nil } +func (m *CreateUpdateOrders) validateOriginDutyLocationID(formats strfmt.Registry) error { + if swag.IsZero(m.OriginDutyLocationID) { // not required + return nil + } + + if err := validate.FormatOf("origin_duty_location_id", "body", "uuid", m.OriginDutyLocationID.String(), formats); err != nil { + return err + } + + return nil +} + func (m *CreateUpdateOrders) validateReportByDate(formats strfmt.Registry) error { if err := validate.Required("report_by_date", "body", m.ReportByDate); err != nil { @@ -264,6 +311,10 @@ func (m *CreateUpdateOrders) ContextValidate(ctx context.Context, formats strfmt res = append(res, err) } + if err := m.contextValidateGrade(ctx, formats); err != nil { + res = append(res, err) + } + if err := m.contextValidateOrdersType(ctx, formats); err != nil { res = append(res, err) } @@ -299,6 +350,27 @@ func (m *CreateUpdateOrders) contextValidateDepartmentIndicator(ctx context.Cont return nil } +func (m *CreateUpdateOrders) contextValidateGrade(ctx context.Context, formats strfmt.Registry) error { + + if m.Grade != nil { + + if swag.IsZero(m.Grade) { // not required + return nil + } + + if err := m.Grade.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("grade") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("grade") + } + return err + } + } + + return nil +} + func (m *CreateUpdateOrders) contextValidateOrdersType(ctx context.Context, formats strfmt.Registry) error { if m.OrdersType != nil { diff --git a/pkg/gen/internalmessages/order_pay_grade.go b/pkg/gen/internalmessages/order_pay_grade.go new file mode 100644 index 00000000000..0b783c8fc4e --- /dev/null +++ b/pkg/gen/internalmessages/order_pay_grade.go @@ -0,0 +1,159 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package internalmessages + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "encoding/json" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/validate" +) + +// OrderPayGrade Rank +// +// swagger:model OrderPayGrade +type OrderPayGrade string + +func NewOrderPayGrade(value OrderPayGrade) *OrderPayGrade { + return &value +} + +// Pointer returns a pointer to a freshly-allocated OrderPayGrade. +func (m OrderPayGrade) Pointer() *OrderPayGrade { + return &m +} + +const ( + + // OrderPayGradeE1 captures enum value "E_1" + OrderPayGradeE1 OrderPayGrade = "E_1" + + // OrderPayGradeE2 captures enum value "E_2" + OrderPayGradeE2 OrderPayGrade = "E_2" + + // OrderPayGradeE3 captures enum value "E_3" + OrderPayGradeE3 OrderPayGrade = "E_3" + + // OrderPayGradeE4 captures enum value "E_4" + OrderPayGradeE4 OrderPayGrade = "E_4" + + // OrderPayGradeE5 captures enum value "E_5" + OrderPayGradeE5 OrderPayGrade = "E_5" + + // OrderPayGradeE6 captures enum value "E_6" + OrderPayGradeE6 OrderPayGrade = "E_6" + + // OrderPayGradeE7 captures enum value "E_7" + OrderPayGradeE7 OrderPayGrade = "E_7" + + // OrderPayGradeE8 captures enum value "E_8" + OrderPayGradeE8 OrderPayGrade = "E_8" + + // OrderPayGradeE9 captures enum value "E_9" + OrderPayGradeE9 OrderPayGrade = "E_9" + + // OrderPayGradeE9SPECIALSENIORENLISTED captures enum value "E_9_SPECIAL_SENIOR_ENLISTED" + OrderPayGradeE9SPECIALSENIORENLISTED OrderPayGrade = "E_9_SPECIAL_SENIOR_ENLISTED" + + // OrderPayGradeO1ACADEMYGRADUATE captures enum value "O_1_ACADEMY_GRADUATE" + OrderPayGradeO1ACADEMYGRADUATE OrderPayGrade = "O_1_ACADEMY_GRADUATE" + + // OrderPayGradeO2 captures enum value "O_2" + OrderPayGradeO2 OrderPayGrade = "O_2" + + // OrderPayGradeO3 captures enum value "O_3" + OrderPayGradeO3 OrderPayGrade = "O_3" + + // OrderPayGradeO4 captures enum value "O_4" + OrderPayGradeO4 OrderPayGrade = "O_4" + + // OrderPayGradeO5 captures enum value "O_5" + OrderPayGradeO5 OrderPayGrade = "O_5" + + // OrderPayGradeO6 captures enum value "O_6" + OrderPayGradeO6 OrderPayGrade = "O_6" + + // OrderPayGradeO7 captures enum value "O_7" + OrderPayGradeO7 OrderPayGrade = "O_7" + + // OrderPayGradeO8 captures enum value "O_8" + OrderPayGradeO8 OrderPayGrade = "O_8" + + // OrderPayGradeO9 captures enum value "O_9" + OrderPayGradeO9 OrderPayGrade = "O_9" + + // OrderPayGradeO10 captures enum value "O_10" + OrderPayGradeO10 OrderPayGrade = "O_10" + + // OrderPayGradeW1 captures enum value "W_1" + OrderPayGradeW1 OrderPayGrade = "W_1" + + // OrderPayGradeW2 captures enum value "W_2" + OrderPayGradeW2 OrderPayGrade = "W_2" + + // OrderPayGradeW3 captures enum value "W_3" + OrderPayGradeW3 OrderPayGrade = "W_3" + + // OrderPayGradeW4 captures enum value "W_4" + OrderPayGradeW4 OrderPayGrade = "W_4" + + // OrderPayGradeW5 captures enum value "W_5" + OrderPayGradeW5 OrderPayGrade = "W_5" + + // OrderPayGradeAVIATIONCADET captures enum value "AVIATION_CADET" + OrderPayGradeAVIATIONCADET OrderPayGrade = "AVIATION_CADET" + + // OrderPayGradeCIVILIANEMPLOYEE captures enum value "CIVILIAN_EMPLOYEE" + OrderPayGradeCIVILIANEMPLOYEE OrderPayGrade = "CIVILIAN_EMPLOYEE" + + // OrderPayGradeACADEMYCADET captures enum value "ACADEMY_CADET" + OrderPayGradeACADEMYCADET OrderPayGrade = "ACADEMY_CADET" + + // OrderPayGradeMIDSHIPMAN captures enum value "MIDSHIPMAN" + OrderPayGradeMIDSHIPMAN OrderPayGrade = "MIDSHIPMAN" +) + +// for schema +var orderPayGradeEnum []interface{} + +func init() { + var res []OrderPayGrade + if err := json.Unmarshal([]byte(`["E_1","E_2","E_3","E_4","E_5","E_6","E_7","E_8","E_9","E_9_SPECIAL_SENIOR_ENLISTED","O_1_ACADEMY_GRADUATE","O_2","O_3","O_4","O_5","O_6","O_7","O_8","O_9","O_10","W_1","W_2","W_3","W_4","W_5","AVIATION_CADET","CIVILIAN_EMPLOYEE","ACADEMY_CADET","MIDSHIPMAN"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + orderPayGradeEnum = append(orderPayGradeEnum, v) + } +} + +func (m OrderPayGrade) validateOrderPayGradeEnum(path, location string, value OrderPayGrade) error { + if err := validate.EnumCase(path, location, value, orderPayGradeEnum, true); err != nil { + return err + } + return nil +} + +// Validate validates this order pay grade +func (m OrderPayGrade) Validate(formats strfmt.Registry) error { + var res []error + + // value enum + if err := m.validateOrderPayGradeEnum("", "body", m); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +// ContextValidate validates this order pay grade based on context it is used +func (m OrderPayGrade) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} diff --git a/pkg/handlers/internalapi/orders.go b/pkg/handlers/internalapi/orders.go index aafb6903f5b..fe15e223800 100644 --- a/pkg/handlers/internalapi/orders.go +++ b/pkg/handlers/internalapi/orders.go @@ -294,6 +294,19 @@ func (h UpdateOrdersHandler) Handle(params ordersop.UpdateOrdersParams) middlewa return handlers.ResponseForError(appCtx.Logger(), err), err } + if payload.OriginDutyLocationID != "" { + originDutyLocationID, errorOrigin := uuid.FromString(payload.OriginDutyLocationID.String()) + if errorOrigin != nil { + return handlers.ResponseForError(appCtx.Logger(), errorOrigin), errorOrigin + } + originDutyLocation, errorOrigin := models.FetchDutyLocation(appCtx.DB(), originDutyLocationID) + if errorOrigin != nil { + return handlers.ResponseForError(appCtx.Logger(), errorOrigin), errorOrigin + } + order.OriginDutyLocation = &originDutyLocation + order.OriginDutyLocationID = &originDutyLocationID + } + if payload.OrdersType == nil { errMsg := "missing required field: OrdersType" return handlers.ResponseForError(appCtx.Logger(), errors.New(errMsg)), apperror.NewBadDataError("missing required field: OrdersType") @@ -310,6 +323,7 @@ func (h UpdateOrdersHandler) Handle(params ordersop.UpdateOrdersParams) middlewa order.NewDutyLocation = dutyLocation order.TAC = payload.Tac order.SAC = payload.Sac + order.Grade = (*string)(payload.Grade) if payload.DepartmentIndicator != nil { order.DepartmentIndicator = handlers.FmtString(string(*payload.DepartmentIndicator)) diff --git a/src/components/Customer/DodInfoForm/DodInfoForm.jsx b/src/components/Customer/DodInfoForm/DodInfoForm.jsx index a2957ffa46f..4c89aee32db 100644 --- a/src/components/Customer/DodInfoForm/DodInfoForm.jsx +++ b/src/components/Customer/DodInfoForm/DodInfoForm.jsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { Formik } from 'formik'; import * as Yup from 'yup'; -import { ORDERS_RANK_OPTIONS } from 'constants/orders'; +import { ORDERS_PAY_GRADE_OPTIONS } from 'constants/orders'; import { SERVICE_MEMBER_AGENCY_LABELS } from 'content/serviceMemberAgencies'; import { Form } from 'components/form/Form'; import TextField from 'components/form/fields/TextField/TextField'; @@ -15,14 +15,14 @@ import formStyles from 'styles/form.module.scss'; const DodInfoForm = ({ initialValues, onSubmit, onBack }) => { const branchOptions = dropdownInputOptions(SERVICE_MEMBER_AGENCY_LABELS); - const rankOptions = dropdownInputOptions(ORDERS_RANK_OPTIONS); + const payGradeOptions = dropdownInputOptions(ORDERS_PAY_GRADE_OPTIONS); const validationSchema = Yup.object().shape({ affiliation: Yup.mixed().oneOf(Object.keys(SERVICE_MEMBER_AGENCY_LABELS)).required('Required'), edipi: Yup.string() .matches(/[0-9]{10}/, 'Enter a 10-digit DOD ID number') .required('Required'), - rank: Yup.mixed().oneOf(Object.keys(ORDERS_RANK_OPTIONS)).required('Required'), + grade: Yup.mixed().oneOf(Object.keys(ORDERS_PAY_GRADE_OPTIONS)).required('Required'), }); return ( @@ -49,7 +49,7 @@ const DodInfoForm = ({ initialValues, onSubmit, onBack }) => { inputMode="numeric" pattern="[0-9]{10}" /> - +
@@ -70,7 +70,7 @@ DodInfoForm.propTypes = { initialValues: PropTypes.shape({ affiliation: PropTypes.string, edipi: PropTypes.string, - rank: PropTypes.string, + grade: PropTypes.string, }).isRequired, onSubmit: PropTypes.func.isRequired, onBack: PropTypes.func.isRequired, diff --git a/src/components/Customer/DodInfoForm/DodInfoForm.stories.jsx b/src/components/Customer/DodInfoForm/DodInfoForm.stories.jsx index c045e1e6403..e7953cace96 100644 --- a/src/components/Customer/DodInfoForm/DodInfoForm.stories.jsx +++ b/src/components/Customer/DodInfoForm/DodInfoForm.stories.jsx @@ -20,7 +20,7 @@ export const WithInitialValues = (argTypes) => ( initialValues={{ affiliation: 'ARMY', edipi: '9999999999', - rank: 'E_2', + grade: 'E_2', }} onSubmit={argTypes.onSubmit} onBack={argTypes.onBack} diff --git a/src/components/Customer/DodInfoForm/DodInfoForm.test.jsx b/src/components/Customer/DodInfoForm/DodInfoForm.test.jsx index c5925724ee5..1d660830da6 100644 --- a/src/components/Customer/DodInfoForm/DodInfoForm.test.jsx +++ b/src/components/Customer/DodInfoForm/DodInfoForm.test.jsx @@ -7,7 +7,7 @@ import DodInfoForm from './DodInfoForm'; describe('DodInfoForm component', () => { const testProps = { onSubmit: jest.fn().mockImplementation(() => Promise.resolve()), - initialValues: { affiliation: '', edipi: '', rank: '' }, + initialValues: { affiliation: '', edipi: '', grade: '' }, onBack: jest.fn(), }; @@ -66,7 +66,7 @@ describe('DodInfoForm component', () => { await waitFor(() => { expect(testProps.onSubmit).toHaveBeenCalledWith( - expect.objectContaining({ affiliation: 'NAVY', edipi: '1234567890', rank: 'E_5' }), + expect.objectContaining({ affiliation: 'NAVY', edipi: '1234567890', grade: 'E_5' }), expect.anything(), ); }); diff --git a/src/components/Customer/Review/ProfileTable/ProfileTable.jsx b/src/components/Customer/Review/ProfileTable/ProfileTable.jsx index f4ade2e429d..cdcc98a98be 100644 --- a/src/components/Customer/Review/ProfileTable/ProfileTable.jsx +++ b/src/components/Customer/Review/ProfileTable/ProfileTable.jsx @@ -17,7 +17,7 @@ const ProfileTable = ({ lastName, onEditClick, postalCode, - rank, + payGrade, state, streetAddress1, streetAddress2, @@ -57,7 +57,7 @@ const ProfileTable = ({ Pay grade - {rank} + {payGrade} DOD ID# @@ -103,7 +103,7 @@ ProfileTable.propTypes = { lastName: string.isRequired, onEditClick: func.isRequired, postalCode: string.isRequired, - rank: string.isRequired, + payGrade: string.isRequired, state: string.isRequired, streetAddress1: string.isRequired, streetAddress2: string, diff --git a/src/components/Customer/Review/ProfileTable/ProfileTable.stories.jsx b/src/components/Customer/Review/ProfileTable/ProfileTable.stories.jsx index 03064ffec3c..19eab426fa5 100644 --- a/src/components/Customer/Review/ProfileTable/ProfileTable.stories.jsx +++ b/src/components/Customer/Review/ProfileTable/ProfileTable.stories.jsx @@ -26,7 +26,7 @@ const defaultProps = { firstName: 'Jason', lastName: 'Ash', affiliation: 'Air Force', - rank: 'E-5', + payGrade: 'E-5', edipi: '9999999999', currentDutyLocationName: 'Buckley AFB', telephone: '(999) 999-9999', diff --git a/src/components/Customer/Review/ServiceInfoDisplay/ServiceInfoDisplay.jsx b/src/components/Customer/Review/ServiceInfoDisplay/ServiceInfoDisplay.jsx index a9e2915f4cd..24576645bf9 100644 --- a/src/components/Customer/Review/ServiceInfoDisplay/ServiceInfoDisplay.jsx +++ b/src/components/Customer/Review/ServiceInfoDisplay/ServiceInfoDisplay.jsx @@ -17,7 +17,7 @@ const ServiceInfoDisplay = ({ showMessage, lastName, editURL, - rank, + payGrade, }) => { return (
@@ -47,7 +47,7 @@ const ServiceInfoDisplay = ({
Pay grade
-
{rank}
+
{payGrade}
@@ -76,7 +76,7 @@ ServiceInfoDisplay.propTypes = { showMessage: bool, lastName: string.isRequired, editURL: string, - rank: string.isRequired, + payGrade: string.isRequired, }; ServiceInfoDisplay.defaultProps = { diff --git a/src/components/Customer/Review/ServiceInfoDisplay/ServiceInfoDisplay.stories.jsx b/src/components/Customer/Review/ServiceInfoDisplay/ServiceInfoDisplay.stories.jsx index ba611c034ee..b4a3143f4f5 100644 --- a/src/components/Customer/Review/ServiceInfoDisplay/ServiceInfoDisplay.stories.jsx +++ b/src/components/Customer/Review/ServiceInfoDisplay/ServiceInfoDisplay.stories.jsx @@ -21,7 +21,7 @@ const defaultProps = { firstName: 'Jason', lastName: 'Ash', affiliation: 'Air Force', - rank: 'E-5', + payGrade: 'E-5', edipi: '9999999999', originDutyLocationName: 'Buckley AFB', originTransportationOfficeName: 'Buckley AFB', diff --git a/src/components/Customer/Review/ServiceInfoDisplay/ServiceInfoDisplay.test.jsx b/src/components/Customer/Review/ServiceInfoDisplay/ServiceInfoDisplay.test.jsx index 32b19c9943b..298654d6955 100644 --- a/src/components/Customer/Review/ServiceInfoDisplay/ServiceInfoDisplay.test.jsx +++ b/src/components/Customer/Review/ServiceInfoDisplay/ServiceInfoDisplay.test.jsx @@ -10,7 +10,7 @@ describe('ServiceInfoDisplay component', () => { firstName: 'Jason', lastName: 'Ash', affiliation: 'Air Force', - rank: 'E-5', + payGrade: 'E-5', edipi: '9999999999', originDutyLocationName: 'Buckley AFB', originTransportationOfficeName: 'Buckley AFB', @@ -36,11 +36,11 @@ describe('ServiceInfoDisplay component', () => { expect(branch.nextElementSibling.textContent).toBe(testProps.affiliation); - const rank = screen.getByText('Pay grade'); + const payGrade = screen.getByText('Pay grade'); - expect(rank).toBeInTheDocument(); + expect(payGrade).toBeInTheDocument(); - expect(rank.nextElementSibling.textContent).toBe(testProps.rank); + expect(payGrade.nextElementSibling.textContent).toBe(testProps.payGrade); const dodId = screen.getByText('DoD ID#'); diff --git a/src/components/Customer/Review/Summary/Summary.jsx b/src/components/Customer/Review/Summary/Summary.jsx index c057b787569..d507b6cde4a 100644 --- a/src/components/Customer/Review/Summary/Summary.jsx +++ b/src/components/Customer/Review/Summary/Summary.jsx @@ -18,7 +18,7 @@ import NTSRShipmentCard from 'components/Customer/Review/ShipmentCard/NTSRShipme import NTSShipmentCard from 'components/Customer/Review/ShipmentCard/NTSShipmentCard/NTSShipmentCard'; import PPMShipmentCard from 'components/Customer/Review/ShipmentCard/PPMShipmentCard/PPMShipmentCard'; import SectionWrapper from 'components/Customer/SectionWrapper'; -import { ORDERS_BRANCH_OPTIONS, ORDERS_RANK_OPTIONS } from 'constants/orders'; +import { ORDERS_BRANCH_OPTIONS, ORDERS_PAY_GRADE_OPTIONS } from 'constants/orders'; import { customerRoutes } from 'constants/routes'; import { deleteMTOShipment, getMTOShipmentsForMove } from 'services/internalApi'; import { MOVE_STATUSES, SHIPMENT_OPTIONS } from 'shared/constants'; @@ -291,7 +291,9 @@ export class Summary extends Component { onEditClick={this.handleEditClick} lastName={serviceMember.last_name} postalCode={serviceMember.residential_address.postalCode} - rank={ORDERS_RANK_OPTIONS[serviceMember?.rank] || ''} + payGrade={ + ORDERS_PAY_GRADE_OPTIONS[currentOrders?.grade] || ORDERS_PAY_GRADE_OPTIONS[serviceMember?.rank] || '' + } state={serviceMember.residential_address.state} streetAddress1={serviceMember.residential_address.streetAddress1} streetAddress2={serviceMember.residential_address.streetAddress2} diff --git a/src/components/Customer/ServiceInfoForm/ServiceInfoForm.jsx b/src/components/Customer/ServiceInfoForm/ServiceInfoForm.jsx index 9dfdb482219..cc52167e9e6 100644 --- a/src/components/Customer/ServiceInfoForm/ServiceInfoForm.jsx +++ b/src/components/Customer/ServiceInfoForm/ServiceInfoForm.jsx @@ -4,7 +4,7 @@ import { Formik } from 'formik'; import * as Yup from 'yup'; import { Grid } from '@trussworks/react-uswds'; -import { ORDERS_RANK_OPTIONS } from 'constants/orders'; +import { ORDERS_PAY_GRADE_OPTIONS } from 'constants/orders'; import { SERVICE_MEMBER_AGENCY_LABELS } from 'content/serviceMemberAgencies'; import { Form } from 'components/form/Form'; import TextField from 'components/form/fields/TextField/TextField'; @@ -18,7 +18,7 @@ import { DutyLocationShape } from 'types/dutyLocation'; const ServiceInfoForm = ({ initialValues, onSubmit, onCancel }) => { const branchOptions = dropdownInputOptions(SERVICE_MEMBER_AGENCY_LABELS); - const rankOptions = dropdownInputOptions(ORDERS_RANK_OPTIONS); + const payGradeOptions = dropdownInputOptions(ORDERS_PAY_GRADE_OPTIONS); const validationSchema = Yup.object().shape({ first_name: Yup.string().required('Required'), @@ -29,7 +29,7 @@ const ServiceInfoForm = ({ initialValues, onSubmit, onCancel }) => { edipi: Yup.string() .matches(/[0-9]{10}/, 'Enter a 10-digit DOD ID number') .required('Required'), - rank: Yup.mixed().oneOf(Object.keys(ORDERS_RANK_OPTIONS)).required('Required'), + grade: Yup.mixed().oneOf(Object.keys(ORDERS_PAY_GRADE_OPTIONS)).required('Required'), current_location: Yup.object().required('Required'), }); @@ -72,7 +72,7 @@ const ServiceInfoForm = ({ initialValues, onSubmit, onCancel }) => { - + diff --git a/src/components/Customer/ServiceInfoForm/ServiceInfoForm.stories.jsx b/src/components/Customer/ServiceInfoForm/ServiceInfoForm.stories.jsx index 354ecc287c8..6acad90f4d5 100644 --- a/src/components/Customer/ServiceInfoForm/ServiceInfoForm.stories.jsx +++ b/src/components/Customer/ServiceInfoForm/ServiceInfoForm.stories.jsx @@ -20,7 +20,7 @@ export const DefaultState = (argTypes) => ( suffix: '', affiliation: '', edipi: '', - rank: '', + grade: '', current_location: {}, }} onSubmit={argTypes.onSubmit} @@ -37,7 +37,7 @@ export const WithInitialValues = (argTypes) => ( suffix: 'Mr.', affiliation: 'ARMY', edipi: '9999999999', - rank: 'E_2', + grade: 'E_2', current_location: { address: { city: 'Los Angeles', diff --git a/src/components/Customer/ServiceInfoForm/ServiceInfoForm.test.jsx b/src/components/Customer/ServiceInfoForm/ServiceInfoForm.test.jsx index ae36f317dea..6d34ec147ae 100644 --- a/src/components/Customer/ServiceInfoForm/ServiceInfoForm.test.jsx +++ b/src/components/Customer/ServiceInfoForm/ServiceInfoForm.test.jsx @@ -138,7 +138,7 @@ describe('ServiceInfoForm', () => { suffix: '', affiliation: '', edipi: '', - rank: '', + grade: '', current_location: {}, }, newDutyLocation: {}, @@ -167,9 +167,9 @@ describe('ServiceInfoForm', () => { expect(dodInput).toBeInstanceOf(HTMLInputElement); expect(dodInput).toBeRequired(); - const rankInput = await screen.findByLabelText('Pay grade'); - expect(rankInput).toBeInstanceOf(HTMLSelectElement); - expect(rankInput).toBeRequired(); + const payGradeInput = await screen.findByLabelText('Pay grade'); + expect(payGradeInput).toBeInstanceOf(HTMLSelectElement); + expect(payGradeInput).toBeRequired(); expect(await screen.findByLabelText('Current duty location')).toBeInstanceOf(HTMLInputElement); }); @@ -234,7 +234,7 @@ describe('ServiceInfoForm', () => { last_name: 'Spaceman', affiliation: 'NAVY', edipi: '1234567890', - rank: 'E_5', + grade: 'E_5', current_location: { address: { city: 'Test City', diff --git a/src/components/CustomerHeader/CustomerHeader.test.jsx b/src/components/CustomerHeader/CustomerHeader.test.jsx index dccd38f2529..bf5655954e1 100644 --- a/src/components/CustomerHeader/CustomerHeader.test.jsx +++ b/src/components/CustomerHeader/CustomerHeader.test.jsx @@ -48,7 +48,7 @@ describe('CustomerHeader component', () => { it('renders expected values', () => { expect(wrapper.find('[data-testid="nameBlock"]').text()).toContain('Kerry, Smith'); expect(wrapper.find('[data-testid="nameBlock"]').text()).toContain('FKLCTR'); - expect(wrapper.find('[data-testid="deptRank"]').text()).toContain('Navy E-6'); + expect(wrapper.find('[data-testid="deptPayGrade"]').text()).toContain('Navy E-6'); expect(wrapper.find('[data-testid="dodId"]').text()).toContain('DoD ID 999999999'); expect(wrapper.find('[data-testid="infoBlock"]').text()).toContain('JBSA Lackland'); expect(wrapper.find('[data-testid="infoBlock"]').text()).toContain('JB Lewis-McChord'); diff --git a/src/components/CustomerHeader/index.jsx b/src/components/CustomerHeader/index.jsx index adc6c0051d7..64e6f6895e8 100644 --- a/src/components/CustomerHeader/index.jsx +++ b/src/components/CustomerHeader/index.jsx @@ -5,7 +5,7 @@ import styles from './index.module.scss'; import { OrderShape, CustomerShape } from 'types/order'; import { formatCustomerDate, formatLabelReportByDate } from 'utils/formatters'; -import { ORDERS_BRANCH_OPTIONS, ORDERS_RANK_OPTIONS } from 'constants/orders.js'; +import { ORDERS_BRANCH_OPTIONS, ORDERS_PAY_GRADE_OPTIONS } from 'constants/orders.js'; const CustomerHeader = ({ customer, order, moveCode }) => { // eslint-disable-next-line camelcase @@ -32,8 +32,8 @@ const CustomerHeader = ({ customer, order, moveCode }) => {

- - {ORDERS_BRANCH_OPTIONS[`${order.agency}`]} {ORDERS_RANK_OPTIONS[`${order.grade}`]} + + {ORDERS_BRANCH_OPTIONS[`${order.agency}`]} {ORDERS_PAY_GRADE_OPTIONS[`${order.grade}`]} | diff --git a/src/components/Office/AllowancesDetailForm/AllowancesDetailForm.jsx b/src/components/Office/AllowancesDetailForm/AllowancesDetailForm.jsx index 303ce1ecae9..e1b7ed6ee9b 100644 --- a/src/components/Office/AllowancesDetailForm/AllowancesDetailForm.jsx +++ b/src/components/Office/AllowancesDetailForm/AllowancesDetailForm.jsx @@ -10,7 +10,7 @@ import { EntitlementShape } from 'types/order'; import { formatWeight } from 'utils/formatters'; import Hint from 'components/Hint'; -const AllowancesDetailForm = ({ header, entitlements, rankOptions, branchOptions, formIsDisabled }) => { +const AllowancesDetailForm = ({ header, entitlements, payGradeOptions, branchOptions, formIsDisabled }) => { return (

{header &&

{header}

} @@ -72,10 +72,11 @@ const AllowancesDetailForm = ({ header, entitlements, rankOptions, branchOptions isDisabled={formIsDisabled} /> @@ -120,7 +121,7 @@ const AllowancesDetailForm = ({ header, entitlements, rankOptions, branchOptions AllowancesDetailForm.propTypes = { entitlements: EntitlementShape.isRequired, - rankOptions: DropdownArrayOf.isRequired, + payGradeOptions: DropdownArrayOf.isRequired, branchOptions: DropdownArrayOf.isRequired, header: PropTypes.string, formIsDisabled: PropTypes.bool, diff --git a/src/components/Office/AllowancesDetailForm/AllowancesDetailForm.test.jsx b/src/components/Office/AllowancesDetailForm/AllowancesDetailForm.test.jsx index 4246bc012b1..b3bd96d6645 100644 --- a/src/components/Office/AllowancesDetailForm/AllowancesDetailForm.test.jsx +++ b/src/components/Office/AllowancesDetailForm/AllowancesDetailForm.test.jsx @@ -47,7 +47,7 @@ jest.mock('formik', () => ({ const { Formik } = jest.requireActual('formik'); -const rankOptions = [ +const payGradeOptions = [ { key: 'E_1', value: 'E-1' }, { key: 'E_2', value: 'E-2' }, { key: 'E_3', value: 'E-3' }, @@ -83,7 +83,11 @@ describe('AllowancesDetailForm', () => { it('renders the form', async () => { render( - + , ); @@ -95,7 +99,11 @@ describe('AllowancesDetailForm', () => { it('renders the pro-gear hints', async () => { render( - + , ); @@ -108,7 +116,7 @@ describe('AllowancesDetailForm', () => { diff --git a/src/components/Office/EvaluationReportMoveInfo/EvaluationReportMoveInfo.jsx b/src/components/Office/EvaluationReportMoveInfo/EvaluationReportMoveInfo.jsx index 58010d2b603..a3b64366cd5 100644 --- a/src/components/Office/EvaluationReportMoveInfo/EvaluationReportMoveInfo.jsx +++ b/src/components/Office/EvaluationReportMoveInfo/EvaluationReportMoveInfo.jsx @@ -7,7 +7,7 @@ import evaluationReportStyles from './EvaluationReportMoveInfo.module.scss'; import DataTable from 'components/DataTable'; import { CustomerShape } from 'types'; -import { ORDERS_BRANCH_OPTIONS, ORDERS_RANK_OPTIONS } from 'constants/orders'; +import { ORDERS_BRANCH_OPTIONS, ORDERS_PAY_GRADE_OPTIONS } from 'constants/orders'; const EvaluationReportMoveInfo = ({ customerInfo, grade }) => { const customerInfoTableBody = ( @@ -16,7 +16,7 @@ const EvaluationReportMoveInfo = ({ customerInfo, grade }) => {
{customerInfo.phone}
- {ORDERS_RANK_OPTIONS[grade]} + {ORDERS_PAY_GRADE_OPTIONS[grade]}
{ORDERS_BRANCH_OPTIONS[customerInfo.agency] ? ORDERS_BRANCH_OPTIONS[customerInfo.agency] : customerInfo.agency} diff --git a/src/components/Office/EvaluationReportPreview/EvaluationReportPreview.jsx b/src/components/Office/EvaluationReportPreview/EvaluationReportPreview.jsx index d087ff61504..a78994dcb3b 100644 --- a/src/components/Office/EvaluationReportPreview/EvaluationReportPreview.jsx +++ b/src/components/Office/EvaluationReportPreview/EvaluationReportPreview.jsx @@ -12,7 +12,7 @@ import DataTable from 'components/DataTable'; import DataTableWrapper from 'components/DataTableWrapper'; import EvaluationReportList from 'components/Office/DefinitionLists/EvaluationReportList'; import EvaluationReportViolationsList from 'components/Office/DefinitionLists/EvaluationReportViolationsList'; -import { ORDERS_BRANCH_OPTIONS, ORDERS_RANK_OPTIONS } from 'constants/orders'; +import { ORDERS_BRANCH_OPTIONS, ORDERS_PAY_GRADE_OPTIONS } from 'constants/orders'; import { CustomerShape, EvaluationReportShape, ShipmentShape } from 'types'; import { formatDateFromIso, formatQAReportID } from 'utils/formatters'; import { formatDate } from 'shared/dates'; @@ -42,7 +42,7 @@ const EvaluationReportPreview = ({
{customerInfo.phone}
- {ORDERS_RANK_OPTIONS[grade]} + {ORDERS_PAY_GRADE_OPTIONS[grade]}
{ORDERS_BRANCH_OPTIONS[customerInfo.agency] ? ORDERS_BRANCH_OPTIONS[customerInfo.agency] : customerInfo.agency} diff --git a/src/components/Office/EvaluationReportShipmentInfo/EvaluationReportShipmentInfo.jsx b/src/components/Office/EvaluationReportShipmentInfo/EvaluationReportShipmentInfo.jsx index bc07cf9431c..640012e722d 100644 --- a/src/components/Office/EvaluationReportShipmentInfo/EvaluationReportShipmentInfo.jsx +++ b/src/components/Office/EvaluationReportShipmentInfo/EvaluationReportShipmentInfo.jsx @@ -8,7 +8,7 @@ import evaluationReportStyles from './EvaluationReportShipmentInfo.module.scss'; import styles from 'components/Office/EvaluationReportPreview/EvaluationReportPreview.module.scss'; import 'styles/office.scss'; import DataTable from 'components/DataTable'; -import { ORDERS_BRANCH_OPTIONS, ORDERS_RANK_OPTIONS } from 'constants/orders'; +import { ORDERS_BRANCH_OPTIONS, ORDERS_PAY_GRADE_OPTIONS } from 'constants/orders'; import { shipmentTypeLabels } from 'content/shipments'; import EvaluationReportShipmentDisplay from 'components/Office/EvaluationReportShipmentDisplay/EvaluationReportShipmentDisplay'; @@ -33,7 +33,7 @@ const EvaluationReportShipmentInfo = ({
{customerInfo.phone}
- {ORDERS_RANK_OPTIONS[grade]} + {ORDERS_PAY_GRADE_OPTIONS[grade]}
{ORDERS_BRANCH_OPTIONS[customerInfo.agency] ? ORDERS_BRANCH_OPTIONS[customerInfo.agency] : customerInfo.agency} diff --git a/src/components/Office/RequestedShipments/RequestedShipmentsTestData.js b/src/components/Office/RequestedShipments/RequestedShipmentsTestData.js index d4ac3d31287..f572c254a12 100644 --- a/src/components/Office/RequestedShipments/RequestedShipmentsTestData.js +++ b/src/components/Office/RequestedShipments/RequestedShipmentsTestData.js @@ -1,4 +1,4 @@ -import { ORDERS_TYPE, ORDERS_BRANCH_OPTIONS, ORDERS_RANK_OPTIONS } from '../../../constants/orders'; +import { ORDERS_TYPE, ORDERS_BRANCH_OPTIONS, ORDERS_PAY_GRADE_OPTIONS } from '../../../constants/orders'; import { DEPARTMENT_INDICATOR_OPTIONS } from '../../../constants/departmentIndicators'; import { SHIPMENT_OPTIONS, MTOAgentType } from 'shared/constants'; @@ -341,7 +341,7 @@ export const ordersInfo = { export const allowancesInfo = { branch: ORDERS_BRANCH_OPTIONS.NAVY, - rank: ORDERS_RANK_OPTIONS.E_6, + rank: ORDERS_PAY_GRADE_OPTIONS.E_6, weightAllowance: 11000, authorizedWeight: 11000, progear: 2000, diff --git a/src/constants/MoveHistory/Database/OptionFields.js b/src/constants/MoveHistory/Database/OptionFields.js index 869a1bd93dc..75c8d2d27ff 100644 --- a/src/constants/MoveHistory/Database/OptionFields.js +++ b/src/constants/MoveHistory/Database/OptionFields.js @@ -1,6 +1,6 @@ import { ORDERS_BRANCH_OPTIONS, - ORDERS_RANK_OPTIONS, + ORDERS_PAY_GRADE_OPTIONS, ORDERS_TYPE_DETAILS_OPTIONS, ORDERS_TYPE_OPTIONS, ORDERS_DEPARTMENT_INDICATOR, @@ -12,7 +12,7 @@ export default { ...ORDERS_BRANCH_OPTIONS, ...ORDERS_TYPE_DETAILS_OPTIONS, ...ORDERS_TYPE_OPTIONS, - ...ORDERS_RANK_OPTIONS, + ...ORDERS_PAY_GRADE_OPTIONS, ...ORDERS_DEPARTMENT_INDICATOR, ...shipmentDestinationTypes, }; diff --git a/src/constants/MoveHistory/EventTemplates/ApproveShipmentDiversion/approveShipmentDiversion.test.jsx b/src/constants/MoveHistory/EventTemplates/ApproveShipmentDiversion/approveShipmentDiversion.test.jsx index 23688ded5db..3da8733ffe8 100644 --- a/src/constants/MoveHistory/EventTemplates/ApproveShipmentDiversion/approveShipmentDiversion.test.jsx +++ b/src/constants/MoveHistory/EventTemplates/ApproveShipmentDiversion/approveShipmentDiversion.test.jsx @@ -28,4 +28,10 @@ describe('when given an Approved shipment diversion history record', () => { render(template.getDetails(historyRecord)); expect(screen.getByText('HHG shipment #2FA5C')).toBeInTheDocument(); }); + it('displays the proper name in the event name display column', () => { + const template = getTemplate(historyRecord); + + render(template.getEventNameDisplay(historyRecord)); + expect(screen.getByText('Approved shipment')).toBeInTheDocument(); + }); }); diff --git a/src/constants/MoveHistory/EventTemplates/UpdateMTOStatusServiceCounselingCompleted/updateMTOStatusServiceCounselingCompleted.test.jsx b/src/constants/MoveHistory/EventTemplates/UpdateMTOStatusServiceCounselingCompleted/updateMTOStatusServiceCounselingCompleted.test.jsx index 35ec260e8c3..2f921cb9701 100644 --- a/src/constants/MoveHistory/EventTemplates/UpdateMTOStatusServiceCounselingCompleted/updateMTOStatusServiceCounselingCompleted.test.jsx +++ b/src/constants/MoveHistory/EventTemplates/UpdateMTOStatusServiceCounselingCompleted/updateMTOStatusServiceCounselingCompleted.test.jsx @@ -20,4 +20,10 @@ describe('When given a completed services counseling for a move', () => { render(template.getDetails(historyRecord)); expect(screen.getByText('Counseling Completed')).toBeInTheDocument(); }); + it('displays the proper name in the event name display column', () => { + const template = getTemplate(historyRecord); + + render(template.getEventNameDisplay(historyRecord)); + expect(screen.getByText('Updated shipment')).toBeInTheDocument(); + }); }); diff --git a/src/constants/orders.js b/src/constants/orders.js index 121c7ce2009..3b578bcd84b 100644 --- a/src/constants/orders.js +++ b/src/constants/orders.js @@ -32,7 +32,7 @@ export const ORDERS_TYPE_DETAILS_OPTIONS = { DELAYED_APPROVAL: 'Delayed Approval 20 Weeks or More', }; -export const ORDERS_RANK_OPTIONS = { +export const ORDERS_PAY_GRADE_OPTIONS = { E_1: 'E-1', E_2: 'E-2', E_3: 'E-3', diff --git a/src/pages/MyMove/Profile/DodInfo.jsx b/src/pages/MyMove/Profile/DodInfo.jsx index eee4b13722a..283b43c0a5e 100644 --- a/src/pages/MyMove/Profile/DodInfo.jsx +++ b/src/pages/MyMove/Profile/DodInfo.jsx @@ -21,7 +21,7 @@ export const DodInfo = ({ updateServiceMember, serviceMember }) => { const initialValues = { affiliation: serviceMember?.affiliation || '', edipi: serviceMember?.edipi || '', - rank: serviceMember?.rank || '', + grade: serviceMember?.rank || '', }; const handleBack = () => { @@ -37,7 +37,7 @@ export const DodInfo = ({ updateServiceMember, serviceMember }) => { id: serviceMember.id, affiliation: values.affiliation, edipi: values.edipi, - rank: values.rank, + rank: values.grade, }; return patchServiceMember(payload) diff --git a/src/pages/MyMove/Profile/EditOktaInfo.test.jsx b/src/pages/MyMove/Profile/EditOktaInfo.test.jsx index 19af799f76b..0623168cb7c 100644 --- a/src/pages/MyMove/Profile/EditOktaInfo.test.jsx +++ b/src/pages/MyMove/Profile/EditOktaInfo.test.jsx @@ -6,6 +6,7 @@ import userEvent from '@testing-library/user-event'; import { EditOktaInfo } from './EditOktaInfo'; import { customerRoutes } from 'constants/routes'; +import { updateOktaUser } from 'services/internalApi'; const mockNavigate = jest.fn(); jest.mock('react-router-dom', () => ({ @@ -26,11 +27,11 @@ describe('EditOktaInfo page', () => { const testProps = { oktaUser: { id: 'testServiceMemberID', - oktaUsername: 'test@okta.mil', - oktaEmail: 'test@okta.mil', - oktaFirstName: 'Jim', - oktaLastName: 'Dunk', - oktaEdipi: '1234123412', + login: 'test@okta.mil', + email: 'test@okta.mil', + firstName: 'Jim', + lastName: 'Dunk', + cac_edipi: '1234123412', }, serviceMember: { id: 'testServiceMemberId', @@ -50,6 +51,45 @@ describe('EditOktaInfo page', () => { expect(contactHeader).toBeInTheDocument(); }); + it('shows error if no changes were made', async () => { + render( + + + , + ); + + await userEvent.type(screen.getByLabelText('First Name'), 'Bob'); + const saveBtn = screen.getByRole('button', { name: 'Save' }); + await userEvent.click(saveBtn); + + // Check if updateOktaUser is called with the expected arguments + expect(updateOktaUser).toHaveBeenCalledWith({ + profile: { + id: 'testServiceMemberId', // Adjusted to match the received value + login: 'test@okta.mil', + email: 'test@okta.mil', + firstName: 'JimBob', // Adjusted to match the typed value + lastName: 'Dunk', + cac_edipi: '1234123412', + }, + }); + }); + + it('shows error if no changes were made', async () => { + render( + + + , + ); + + const saveBtn = screen.getByRole('button', { name: 'Save' }); + await userEvent.click(saveBtn); + const errorHeader = screen.getByText('No changes were made'); + const errorMessage = screen.getByText('You must make some changes if you want to edit your Okta profile.'); + expect(errorHeader).toBeInTheDocument(); + expect(errorMessage).toBeInTheDocument(); + }); + it('goes back to the profile page when the cancel button is clicked', async () => { render( diff --git a/src/pages/MyMove/Profile/EditOrdersPayGradeAndOriginLocation.test.jsx b/src/pages/MyMove/Profile/EditOrdersPayGradeAndOriginLocation.test.jsx new file mode 100644 index 00000000000..baa25b860ba --- /dev/null +++ b/src/pages/MyMove/Profile/EditOrdersPayGradeAndOriginLocation.test.jsx @@ -0,0 +1,196 @@ +import React from 'react'; +import { render, screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +import { EditServiceInfo } from './EditServiceInfo'; + +import { createOrders, getOrdersForServiceMember, patchOrders } from 'services/internalApi'; + +jest.mock('services/internalApi', () => ({ + ...jest.requireActual('services/internalApi'), + getOrdersForServiceMember: jest.fn().mockImplementation(() => Promise.resolve()), + createOrders: jest.fn().mockImplementation(() => Promise.resolve()), + patchOrders: jest.fn().mockImplementation(() => Promise.resolve()), +})); +const mockNavigate = jest.fn(); +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useNavigate: () => mockNavigate, +})); + +afterEach(() => { + jest.resetAllMocks(); +}); +const testProps = { + serviceMemberId: '123', + context: { flags: { allOrdersTypes: true } }, + updateOrders: jest.fn(), + updateServiceMember: jest.fn(), + setFlashMessage: jest.fn(), +}; +describe('EditServiceInfo page updates orders table information', () => { + it('save button on profile page patches the orders', async () => { + const testOrdersValues = { + id: 'testOrdersId', + orders_type: 'PERMANENT_CHANGE_OF_STATION', + issue_date: '2020-11-08', + report_by_date: '2020-11-26', + has_dependents: false, + new_duty_location: { + address: { + city: 'Des Moines', + country: 'US', + id: 'a4b30b99-4e82-48a6-b736-01662b499d6a', + postalCode: '50309', + state: 'IA', + streetAddress1: '987 Other Avenue', + streetAddress2: 'P.O. Box 1234', + streetAddress3: 'c/o Another Person', + }, + address_id: 'a4b30b99-4e82-48a6-b736-01662b499d6a', + affiliation: 'AIR_FORCE', + created_at: '2020-10-19T17:01:16.114Z', + id: 'f9299768-16d2-4a13-ae39-7087a58b1f62', + name: 'Yuma AFB', + updated_at: '2020-10-19T17:01:16.114Z', + }, + }; + const testServiceMemberValues = { + id: 'testServiceMemberId', + first_name: 'Leo', + last_name: 'Spaceman', + affiliation: 'NAVY', + edipi: '1234567890', + rank: 'E_5', + current_location: { + address: { + city: 'Test City', + id: '25be4d12-fe93-47f1-bbec-1db386dfa67f', + postalCode: '12345', + state: 'NY', + streetAddress1: '123 Main St', + }, + address_id: '25be4d12-fe93-47f1-bbec-1db386dfa67f', + affiliation: 'AIR_FORCE', + created_at: '2021-02-11T16:48:04.117Z', + id: 'a8d6b33c-8370-4e92-8df2-356b8c9d0c1a', + name: 'Luke AFB', + updated_at: '2021-02-11T16:48:04.117Z', + }, + weight_allotment: { + total_weight_self: 7000, + total_weight_self_plus_dependents: 9000, + pro_gear_weight: 2000, + pro_gear_weight_spouse: 500, + }, + }; + createOrders.mockImplementation(() => Promise.resolve(testOrdersValues)); + + render(); + + getOrdersForServiceMember.mockImplementation(() => Promise.resolve(testOrdersValues)); + patchOrders.mockImplementation(() => Promise.resolve(testOrdersValues)); + + const payGradeInput = await screen.findByLabelText('Pay grade'); + await userEvent.selectOptions(payGradeInput, ['E_2']); + + const submitButton = await screen.findByText('Save'); + expect(submitButton).toBeInTheDocument(); + await userEvent.click(submitButton); + + await waitFor(() => { + expect(patchOrders).toHaveBeenCalled(); + }); + + expect(testProps.updateOrders).toHaveBeenCalledWith(testOrdersValues); + expect(testProps.setFlashMessage).toHaveBeenCalledWith( + 'EDIT_SERVICE_INFO_SUCCESS', + 'info', + `Your weight entitlement is now 7,000 lbs.`, + 'Your changes have been saved. Note that the entitlement has also changed.', + ); + }); + + it('if pay grade does not change, entitlement does not change', async () => { + const testOrdersValues = { + grade: 'E_5', + id: 'testOrdersId', + orders_type: 'PERMANENT_CHANGE_OF_STATION', + issue_date: '2020-11-08', + report_by_date: '2020-11-26', + has_dependents: false, + new_duty_location: { + address: { + city: 'Des Moines', + country: 'US', + id: 'a4b30b99-4e82-48a6-b736-01662b499d6a', + postalCode: '50309', + state: 'IA', + streetAddress1: '987 Other Avenue', + streetAddress2: 'P.O. Box 1234', + streetAddress3: 'c/o Another Person', + }, + address_id: 'a4b30b99-4e82-48a6-b736-01662b499d6a', + affiliation: 'AIR_FORCE', + created_at: '2020-10-19T17:01:16.114Z', + id: 'f9299768-16d2-4a13-ae39-7087a58b1f62', + name: 'Yuma AFB', + updated_at: '2020-10-19T17:01:16.114Z', + }, + }; + const testServiceMemberValues = { + id: 'testServiceMemberId', + first_name: 'Leo', + last_name: 'Spaceman', + affiliation: 'NAVY', + edipi: '1234567890', + rank: 'E_5', + current_location: { + address: { + city: 'Test City', + id: '25be4d12-fe93-47f1-bbec-1db386dfa67f', + postalCode: '12345', + state: 'NY', + streetAddress1: '123 Main St', + }, + address_id: '25be4d12-fe93-47f1-bbec-1db386dfa67f', + affiliation: 'AIR_FORCE', + created_at: '2021-02-11T16:48:04.117Z', + id: 'a8d6b33c-8370-4e92-8df2-356b8c9d0c1a', + name: 'Luke AFB', + updated_at: '2021-02-11T16:48:04.117Z', + }, + weight_allotment: { + total_weight_self: 7000, + total_weight_self_plus_dependents: 9000, + pro_gear_weight: 2000, + pro_gear_weight_spouse: 500, + }, + }; + createOrders.mockImplementation(() => Promise.resolve(testOrdersValues)); + + render(); + + getOrdersForServiceMember.mockImplementation(() => Promise.resolve(testOrdersValues)); + patchOrders.mockImplementation(() => Promise.resolve(testOrdersValues)); + + const payGradeInput = await screen.findByLabelText('Pay grade'); + await userEvent.selectOptions(payGradeInput, ['E_5']); + + const submitButton = await screen.findByText('Save'); + expect(submitButton).toBeInTheDocument(); + await userEvent.click(submitButton); + + await waitFor(() => { + expect(patchOrders).toHaveBeenCalled(); + }); + + expect(testProps.updateOrders).toHaveBeenCalledWith(testOrdersValues); + expect(testProps.setFlashMessage).toHaveBeenCalledWith( + 'EDIT_SERVICE_INFO_SUCCESS', + 'success', + '', + 'Your changes have been saved.', + ); + }); +}); diff --git a/src/pages/MyMove/Profile/EditServiceInfo.jsx b/src/pages/MyMove/Profile/EditServiceInfo.jsx index 95ea84b388d..78d5b9a5db6 100644 --- a/src/pages/MyMove/Profile/EditServiceInfo.jsx +++ b/src/pages/MyMove/Profile/EditServiceInfo.jsx @@ -5,8 +5,11 @@ import { connect } from 'react-redux'; import { useNavigate } from 'react-router-dom'; import ServiceInfoForm from 'components/Customer/ServiceInfoForm/ServiceInfoForm'; -import { patchServiceMember, getResponseError } from 'services/internalApi'; -import { updateServiceMember as updateServiceMemberAction } from 'store/entities/actions'; +import { patchServiceMember, patchOrders, getResponseError } from 'services/internalApi'; +import { + updateServiceMember as updateServiceMemberAction, + updateOrders as updateOrdersAction, +} from 'store/entities/actions'; import { setFlashMessage as setFlashMessageAction } from 'store/flash/actions'; import { selectServiceMemberFromLoggedInUser, @@ -17,11 +20,13 @@ import { generalRoutes, customerRoutes } from 'constants/routes'; import { OrdersShape, ServiceMemberShape } from 'types/customerShapes'; import { formatWeight } from 'utils/formatters'; import NotificationScrollToTop from 'components/NotificationScrollToTop'; +import { formatDateForSwagger } from 'shared/dates'; export const EditServiceInfo = ({ serviceMember, currentOrders, updateServiceMember, + updateOrders, setFlashMessage, moveIsInDraft, }) => { @@ -42,13 +47,14 @@ export const EditServiceInfo = ({ suffix: serviceMember?.suffix || '', affiliation: serviceMember?.affiliation || '', edipi: serviceMember?.edipi || '', - rank: currentOrders?.grade || '', + grade: currentOrders?.grade || '', current_location: currentOrders?.origin_duty_location || {}, + orders_type: currentOrders?.orders_type || '', + departmentIndicator: currentOrders?.department_indicator, }; const handleSubmit = (values) => { - const entitlementCouldChange = values.rank !== currentOrders.grade; - + const entitlementCouldChange = values.grade !== currentOrders.grade; const payload = { id: serviceMember.id, first_name: values.first_name, @@ -57,11 +63,11 @@ export const EditServiceInfo = ({ suffix: values.suffix, affiliation: values.affiliation, edipi: values.edipi, - rank: values.rank, + rank: values.grade, current_location_id: values.current_location.id, }; - return patchServiceMember(payload) + patchServiceMember(payload) .then((response) => { updateServiceMember(response); if (entitlementCouldChange) { @@ -81,12 +87,49 @@ export const EditServiceInfo = ({ navigate(customerRoutes.PROFILE_PATH); }) .catch((e) => { - // TODO - error handling - below is rudimentary error handling to approximate existing UX // Error shape: https://github.com/swagger-api/swagger-js/blob/master/docs/usage/http-client.md#errors const { response } = e; const errorMessage = getResponseError(response, 'failed to update service member due to server error'); setServerError(errorMessage); }); + + const ordersPayload = { + grade: values.grade, + origin_duty_location_id: values.current_location.id, + service_member_id: serviceMember.id, + id: currentOrders.id, + new_duty_location_id: currentOrders.new_duty_location.id, + has_dependents: currentOrders.has_dependents, + issue_date: formatDateForSwagger(currentOrders.issue_date), + report_by_date: formatDateForSwagger(currentOrders.report_by_date), + spouse_has_pro_gear: currentOrders.spouse_has_pro_gear, + orders_type: currentOrders.orders_type, + }; + patchOrders(ordersPayload) + .then((response) => { + updateOrders(response); + if (entitlementCouldChange) { + const weightAllowance = currentOrders?.has_dependents + ? serviceMember.weight_allotment.total_weight_self_plus_dependents + : serviceMember.weight_allotment.total_weight_self; + setFlashMessage( + 'EDIT_SERVICE_INFO_SUCCESS', + 'info', + `Your weight entitlement is now ${formatWeight(weightAllowance)}.`, + 'Your changes have been saved. Note that the entitlement has also changed.', + ); + } else { + setFlashMessage('EDIT_SERVICE_INFO_SUCCESS', 'success', '', 'Your changes have been saved.'); + } + + navigate(customerRoutes.PROFILE_PATH); + }) + .catch((e) => { + // Error shape: https://github.com/swagger-api/swagger-js/blob/master/docs/usage/http-client.md#errors + const { response } = e; + const errorMessage = getResponseError(response, 'failed to update orders due to server error'); + setServerError(errorMessage); + }); }; const handleCancel = () => { @@ -113,6 +156,7 @@ export const EditServiceInfo = ({ EditServiceInfo.propTypes = { updateServiceMember: PropTypes.func.isRequired, + updateOrders: PropTypes.func.isRequired, setFlashMessage: PropTypes.func.isRequired, serviceMember: ServiceMemberShape.isRequired, currentOrders: OrdersShape.isRequired, @@ -125,6 +169,7 @@ EditServiceInfo.defaultProps = { const mapDispatchToProps = { updateServiceMember: updateServiceMemberAction, + updateOrders: updateOrdersAction, setFlashMessage: setFlashMessageAction, }; diff --git a/src/pages/MyMove/Profile/EditServiceInfo.test.jsx b/src/pages/MyMove/Profile/EditServiceInfo.test.jsx index 9856cfccb56..a4a2827ddbf 100644 --- a/src/pages/MyMove/Profile/EditServiceInfo.test.jsx +++ b/src/pages/MyMove/Profile/EditServiceInfo.test.jsx @@ -109,7 +109,7 @@ describe('EditServiceInfo page', () => { expect(mockNavigate).toHaveBeenCalledWith('/service-member/profile'); }); - it('displays a flash message about entitlement when the rank changes', async () => { + it('displays a flash message about entitlement when the pay grade changes', async () => { const testServiceMemberValues = { id: 'testServiceMemberId', first_name: 'Leo', @@ -185,8 +185,8 @@ describe('EditServiceInfo page', () => { />, ); - const rankInput = await screen.findByLabelText('Pay grade'); - await userEvent.selectOptions(rankInput, ['E_2']); + const payGradeInput = await screen.findByLabelText('Pay grade'); + await userEvent.selectOptions(payGradeInput, ['E_2']); const submitButton = await screen.findByText('Save'); expect(submitButton).toBeInTheDocument(); diff --git a/src/pages/MyMove/Profile/Profile.jsx b/src/pages/MyMove/Profile/Profile.jsx index 1e06e9fd70e..33b5c2cbfb4 100644 --- a/src/pages/MyMove/Profile/Profile.jsx +++ b/src/pages/MyMove/Profile/Profile.jsx @@ -19,13 +19,13 @@ import ServiceInfoDisplay from 'components/Customer/Review/ServiceInfoDisplay/Se import OktaInfoDisplay from 'components/Customer/Profile/OktaInfoDisplay/OktaInfoDisplay'; import { customerRoutes, generalRoutes } from 'constants/routes'; import formStyles from 'styles/form.module.scss'; -import { ORDERS_BRANCH_OPTIONS, ORDERS_RANK_OPTIONS } from 'constants/orders'; +import { ORDERS_BRANCH_OPTIONS, ORDERS_PAY_GRADE_OPTIONS } from 'constants/orders'; import { OktaUserInfoShape } from 'types/user'; const Profile = ({ serviceMember, currentOrders, currentBackupContacts, moveIsInDraft, oktaUser }) => { const showMessages = currentOrders.id && !moveIsInDraft; - const rank = currentOrders.grade ?? serviceMember.rank; - const originDutyLocation = currentOrders.origin_duty_location ?? serviceMember.current_location; + const payGrade = currentOrders.grade; + const originDutyLocation = currentOrders.origin_duty_location; const transportationOfficePhoneLines = originDutyLocation?.transportation_office?.phone_lines; const transportationOfficePhone = transportationOfficePhoneLines ? transportationOfficePhoneLines[0] : ''; const backupContact = { @@ -36,7 +36,7 @@ const Profile = ({ serviceMember, currentOrders, currentBackupContacts, moveIsIn // displays the profile data for MilMove & Okta // Profile w/contact info for servicemember & backup contact - // Service info that displays name, branch, rank, DoDID/EDIPI, and current duty location + // Service info that displays name, branch, pay grade, DoDID/EDIPI, and current duty location // okta profile information: username, email, first name, last name, and DoDID/EDIPI return (
@@ -71,7 +71,7 @@ const Profile = ({ serviceMember, currentOrders, currentBackupContacts, moveIsIn originTransportationOfficeName={originDutyLocation?.transportation_office?.name || ''} originTransportationOfficePhone={transportationOfficePhone} affiliation={ORDERS_BRANCH_OPTIONS[serviceMember?.affiliation] || ''} - rank={ORDERS_RANK_OPTIONS[rank] || ''} + payGrade={ORDERS_PAY_GRADE_OPTIONS[payGrade] || ''} edipi={serviceMember?.edipi || ''} editURL={customerRoutes.SERVICE_INFO_EDIT_PATH} isEditable={moveIsInDraft} diff --git a/src/pages/Office/MoveAllowances/MoveAllowances.jsx b/src/pages/Office/MoveAllowances/MoveAllowances.jsx index f2ea197b7a3..c12251d008a 100644 --- a/src/pages/Office/MoveAllowances/MoveAllowances.jsx +++ b/src/pages/Office/MoveAllowances/MoveAllowances.jsx @@ -16,13 +16,13 @@ import { updateAllowance } from 'services/ghcApi'; import LoadingPlaceholder from 'shared/LoadingPlaceholder'; import SomethingWentWrong from 'shared/SomethingWentWrong'; import { useOrdersDocumentQueries } from 'hooks/queries'; -import { ORDERS_BRANCH_OPTIONS, ORDERS_RANK_OPTIONS } from 'constants/orders'; +import { ORDERS_BRANCH_OPTIONS, ORDERS_PAY_GRADE_OPTIONS } from 'constants/orders'; import { dropdownInputOptions } from 'utils/formatters'; import { ORDERS } from 'constants/queryKeys'; import { permissionTypes } from 'constants/permissions'; import Restricted from 'components/Restricted/Restricted'; -const rankDropdownOptions = dropdownInputOptions(ORDERS_RANK_OPTIONS); +const payGradeDropdownOptions = dropdownInputOptions(ORDERS_PAY_GRADE_OPTIONS); const branchDropdownOption = dropdownInputOptions(ORDERS_BRANCH_OPTIONS); @@ -171,7 +171,7 @@ const MoveAllowances = () => { fallback={ { > diff --git a/src/pages/Office/MoveAllowances/MoveAllowances.test.jsx b/src/pages/Office/MoveAllowances/MoveAllowances.test.jsx index e07d5299a58..8cfe6589316 100644 --- a/src/pages/Office/MoveAllowances/MoveAllowances.test.jsx +++ b/src/pages/Office/MoveAllowances/MoveAllowances.test.jsx @@ -150,7 +150,7 @@ describe('MoveAllowances page', () => { expect(screen.getByTestId('proGearWeightSpouseInput')).toHaveDisplayValue('500'); expect(screen.getByTestId('rmeInput')).toHaveDisplayValue('1,000'); expect(screen.getByTestId('branchInput')).toHaveDisplayValue('Army'); - expect(screen.getByTestId('rankInput')).toHaveDisplayValue('E-1'); + expect(screen.getByTestId('payGradeInput')).toHaveDisplayValue('E-1'); expect(screen.getByTestId('sitInput')).toHaveDisplayValue('2'); expect(screen.getByLabelText('OCIE authorized (Army only)')).toBeChecked(); diff --git a/src/pages/Office/ServicesCounselingMoveAllowances/ServicesCounselingMoveAllowances.jsx b/src/pages/Office/ServicesCounselingMoveAllowances/ServicesCounselingMoveAllowances.jsx index 7de131b199b..3c4dcc18816 100644 --- a/src/pages/Office/ServicesCounselingMoveAllowances/ServicesCounselingMoveAllowances.jsx +++ b/src/pages/Office/ServicesCounselingMoveAllowances/ServicesCounselingMoveAllowances.jsx @@ -11,7 +11,7 @@ import AllowancesDetailForm from '../../../components/Office/AllowancesDetailFor import styles from 'styles/documentViewerWithSidebar.module.scss'; import { milmoveLogger } from 'utils/milmoveLog'; -import { ORDERS_BRANCH_OPTIONS, ORDERS_RANK_OPTIONS } from 'constants/orders'; +import { ORDERS_BRANCH_OPTIONS, ORDERS_PAY_GRADE_OPTIONS } from 'constants/orders'; import { ORDERS } from 'constants/queryKeys'; import { servicesCounselingRoutes } from 'constants/routes'; import { useOrdersDocumentQueries } from 'hooks/queries'; @@ -20,7 +20,7 @@ import { dropdownInputOptions } from 'utils/formatters'; import LoadingPlaceholder from 'shared/LoadingPlaceholder'; import SomethingWentWrong from 'shared/SomethingWentWrong'; -const rankDropdownOptions = dropdownInputOptions(ORDERS_RANK_OPTIONS); +const payGradeDropdownOptions = dropdownInputOptions(ORDERS_PAY_GRADE_OPTIONS); const branchDropdownOption = dropdownInputOptions(ORDERS_BRANCH_OPTIONS); @@ -156,7 +156,7 @@ const ServicesCounselingMoveAllowances = () => {
diff --git a/src/pages/Office/ServicesCounselingMoveAllowances/ServicesCounselingMoveAllowances.test.jsx b/src/pages/Office/ServicesCounselingMoveAllowances/ServicesCounselingMoveAllowances.test.jsx index 2ae039bf6f0..682601cd43c 100644 --- a/src/pages/Office/ServicesCounselingMoveAllowances/ServicesCounselingMoveAllowances.test.jsx +++ b/src/pages/Office/ServicesCounselingMoveAllowances/ServicesCounselingMoveAllowances.test.jsx @@ -151,7 +151,7 @@ describe('MoveAllowances page', () => { expect(screen.getByTestId('proGearWeightSpouseInput')).toHaveDisplayValue('500'); expect(screen.getByTestId('rmeInput')).toHaveDisplayValue('1,000'); expect(screen.getByTestId('branchInput')).toHaveDisplayValue('Army'); - expect(screen.getByTestId('rankInput')).toHaveDisplayValue('E-1'); + expect(screen.getByTestId('payGradeInput')).toHaveDisplayValue('E-1'); expect(screen.getByTestId('sitInput')).toHaveDisplayValue('2'); expect(screen.getByLabelText('OCIE authorized (Army only)')).toBeChecked(); diff --git a/src/scenes/Review/EditProfile.jsx b/src/scenes/Review/EditProfile.jsx index 4bfc05d555c..a93d6d0aa16 100644 --- a/src/scenes/Review/EditProfile.jsx +++ b/src/scenes/Review/EditProfile.jsx @@ -6,8 +6,9 @@ import { Field, reduxForm } from 'redux-form'; import SaveCancelButtons from './SaveCancelButtons'; import profileImage from './images/profile.png'; -import { getResponseError, patchServiceMember } from 'services/internalApi'; +import { getResponseError, patchOrders, patchServiceMember } from 'services/internalApi'; import { updateServiceMember as updateServiceMemberAction } from 'store/entities/actions'; +import { updateOrders as updateOrderAction } from 'store/entities/actions'; import { setFlashMessage as setFlashMessageAction } from 'store/flash/actions'; import Alert from 'shared/Alert'; import { SwaggerField } from 'shared/JsonSchemaForm/JsonSchemaField'; @@ -74,7 +75,7 @@ let EditProfileForm = (props) => { originTransportationOfficeName={transportationOfficeName} originTransportationOfficePhone={transportationOfficePhone} affiliation={initialValues.affiliation} - rank={initialValues.rank} + payGrade={initialValues.rank} edipi={initialValues.edipi} isEditable={false} /> @@ -109,11 +110,12 @@ class EditProfile extends Component { fieldValues.current_location_id = fieldValues.current_location.id; fieldValues.id = this.props.serviceMember.id; - if (fieldValues.rank !== this.props.serviceMember.rank) { + + if (fieldValues.rank !== this.props.currentOrders.grade) { entitlementCouldChange = true; } - return patchServiceMember(fieldValues) + patchServiceMember(fieldValues) .then((response) => { // Update Redux with new data this.props.updateServiceMember(response); @@ -141,6 +143,36 @@ class EditProfile extends Component { errorMessage, }); + scrollToTop(); + }); + + patchOrders(fieldValues) + .then((response) => { + // Update Redux with new data + this.props.updateOrders(response); + + if (entitlementCouldChange) { + setFlashMessage( + 'EDIT_PROFILE_SUCCESS', + 'info', + `Your weight entitlement is now ${entitlement.sum.toLocaleString()} lbs.`, + 'Your changes have been saved. Note that the entitlement has also changed.', + ); + } else { + setFlashMessage('EDIT_PROFILE_SUCCESS', 'success', '', 'Your changes have been saved.'); + } + + const { router: navigate } = this.props; + navigate(-1); + }) + .catch((e) => { + // Error shape: https://github.com/swagger-api/swagger-js/blob/master/docs/usage/http-client.md#errors + const { response } = e; + const errorMessage = getResponseError(response, 'failed to update orders due to server error'); + this.setState({ + errorMessage, + }); + scrollToTop(); }); }; @@ -150,8 +182,8 @@ class EditProfile extends Component { const { errorMessage } = this.state; const initialValues = { ...serviceMember, - rank: currentOrders ? currentOrders.grade : serviceMember.rank, - current_location: currentOrders ? currentOrders.origin_duty_location : serviceMember.current_location, + payGrade: currentOrders.grade, + current_location: currentOrders.origin_duty_location, }; return (
@@ -190,7 +222,7 @@ function mapStateToProps(state) { // The move still counts as in draft if there are no orders. moveIsInDraft: selectMoveIsInDraft(state) || !selectCurrentOrders(state), isPpm: selectHasCurrentPPM(state), - schemaRank: get(state, 'swaggerInternal.spec.definitions.ServiceMemberRank', {}), + schemaGrade: get(state, 'swaggerInternal.spec.definitions.OrderPayGrade', {}), schemaAffiliation: get(state, 'swaggerInternal.spec.definitions.Affiliation', {}), entitlement: selectWeightAllotmentsForLoggedInUser(state), }; @@ -198,6 +230,7 @@ function mapStateToProps(state) { const mapDispatchToProps = { updateServiceMember: updateServiceMemberAction, + updateOrders: updateOrderAction, setFlashMessage: setFlashMessageAction, }; diff --git a/src/shared/ComboButton/dropdown.test.js b/src/shared/ComboButton/dropdown.test.js index 67a57c1e095..c0f54f51e2d 100644 --- a/src/shared/ComboButton/dropdown.test.js +++ b/src/shared/ComboButton/dropdown.test.js @@ -1,9 +1,31 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { DropDownItem } from './dropdown'; +import { DropDownItem, DropDown } from './dropdown'; + +const mockOnChange = jest.fn(); +const formik = require('formik'); + +const getShallowWrapper = (withError = false) => { + const meta = withError ? { touched: true, error: 'sample error' } : { touched: false, error: '' }; + formik.useField = jest.fn(() => [ + { + onChange: mockOnChange, + }, + meta, + ]); + return shallow(); +}; describe('DropdownItems', () => { + describe('DropDown is enabled', () => { + it('when clicked onClick is called', () => { + const wrapper = getShallowWrapper(true); + const DropDown = wrapper.find('div'); + DropDown.simulate('click'); + expect(DropDown).toBeDefined(); + }); + }); describe('DropDownItem is enabled', () => { it('when clicked onClick is called', () => { const onClick = jest.fn(); diff --git a/src/utils/branchRankFormatters.js b/src/utils/branchRankFormatters.js index a0dd6f3eb04..0b4b500f620 100644 --- a/src/utils/branchRankFormatters.js +++ b/src/utils/branchRankFormatters.js @@ -1,8 +1,8 @@ -import { ORDERS_BRANCH_OPTIONS, ORDERS_RANK_OPTIONS } from 'constants/orders'; +import { ORDERS_BRANCH_OPTIONS, ORDERS_PAY_GRADE_OPTIONS } from 'constants/orders'; export default function friendlyBranchRank(branch, rank) { const friendlyBranch = ORDERS_BRANCH_OPTIONS[branch]; - const friendlyRank = ORDERS_RANK_OPTIONS[rank]; + const friendlyRank = ORDERS_PAY_GRADE_OPTIONS[rank]; if (friendlyBranch && friendlyRank) { return `${friendlyBranch}, ${friendlyRank}`; } diff --git a/src/utils/milmoveLog.test.js b/src/utils/milmoveLog.test.js index 0732a9097a9..d81f3e807a9 100644 --- a/src/utils/milmoveLog.test.js +++ b/src/utils/milmoveLog.test.js @@ -1,6 +1,6 @@ import { diag, DiagConsoleLogger, DiagLogLevel } from '@opentelemetry/api'; -import { configureLogger } from './milmoveLog'; +import { configureLogger, configureGlobalLogger } from './milmoveLog'; import { OtelLogger } from './otelLogger'; describe('configureLogger', () => { @@ -14,6 +14,10 @@ describe('configureLogger', () => { jest.restoreAllMocks(); }); + it('should configure GlobalLogger', async () => { + configureGlobalLogger(); + }); + it('should configure OtelLogger', async () => { configureLogger('test', { loggingType: 'otel' }); expect(setLoggerMock).toBeCalled(); diff --git a/swagger-def/internal.yaml b/swagger-def/internal.yaml index 4e8fd3e74fe..63300848358 100644 --- a/swagger-def/internal.yaml +++ b/swagger-def/internal.yaml @@ -1635,6 +1635,70 @@ definitions: CIVILIAN_EMPLOYEE: Civilian Employee ACADEMY_CADET: Service Academy Cadet MIDSHIPMAN: Midshipman + OrderPayGrade: + type: string + x-nullable: true + title: Rank + enum: + - E_1 + - E_2 + - E_3 + - E_4 + - E_5 + - E_6 + - E_7 + - E_8 + - E_9 + - E_9_SPECIAL_SENIOR_ENLISTED + - O_1_ACADEMY_GRADUATE + - O_2 + - O_3 + - O_4 + - O_5 + - O_6 + - O_7 + - O_8 + - O_9 + - O_10 + - W_1 + - W_2 + - W_3 + - W_4 + - W_5 + - AVIATION_CADET + - CIVILIAN_EMPLOYEE + - ACADEMY_CADET + - MIDSHIPMAN + x-display-value: + E_1: E-1 + E_2: E-2 + E_3: E-3 + E_4: E-4 + E_5: E-5 + E_6: E-6 + E_7: E-7 + E_8: E-8 + E_9: E-9 + E_9_SPECIAL_SENIOR_ENLISTED: E-9 (Special Senior Enlisted) + O_1_ACADEMY_GRADUATE: O-1 or Service Academy Graduate + O_2: O-2 + O_3: O-3 + O_4: O-4 + O_5: O-5 + O_6: O-6 + O_7: O-7 + O_8: O-8 + O_9: O-9 + O_10: O-10 + W_1: W-1 + W_2: W-2 + W_3: W-3 + W_4: W-4 + W_5: W-5 + AVIATION_CADET: Aviation Cadet + CIVILIAN_EMPLOYEE: Civilian Employee + ACADEMY_CADET: Service Academy Cadet + MIDSHIPMAN: Midshipman DeptIndicator: type: string x-nullable: true @@ -1946,6 +2010,12 @@ definitions: x-nullable: true department_indicator: $ref: '#/definitions/DeptIndicator' + grade: + $ref: '#/definitions/OrderPayGrade' + origin_duty_location_id: + type: string + format: uuid + example: c56a4180-65aa-42ec-a945-5fd21dec0538 required: - service_member_id - issue_date diff --git a/swagger/internal.yaml b/swagger/internal.yaml index 39a3400dbf0..496ed4142f4 100644 --- a/swagger/internal.yaml +++ b/swagger/internal.yaml @@ -1656,6 +1656,70 @@ definitions: CIVILIAN_EMPLOYEE: Civilian Employee ACADEMY_CADET: Service Academy Cadet MIDSHIPMAN: Midshipman + OrderPayGrade: + type: string + x-nullable: true + title: Rank + enum: + - E_1 + - E_2 + - E_3 + - E_4 + - E_5 + - E_6 + - E_7 + - E_8 + - E_9 + - E_9_SPECIAL_SENIOR_ENLISTED + - O_1_ACADEMY_GRADUATE + - O_2 + - O_3 + - O_4 + - O_5 + - O_6 + - O_7 + - O_8 + - O_9 + - O_10 + - W_1 + - W_2 + - W_3 + - W_4 + - W_5 + - AVIATION_CADET + - CIVILIAN_EMPLOYEE + - ACADEMY_CADET + - MIDSHIPMAN + x-display-value: + E_1: E-1 + E_2: E-2 + E_3: E-3 + E_4: E-4 + E_5: E-5 + E_6: E-6 + E_7: E-7 + E_8: E-8 + E_9: E-9 + E_9_SPECIAL_SENIOR_ENLISTED: E-9 (Special Senior Enlisted) + O_1_ACADEMY_GRADUATE: O-1 or Service Academy Graduate + O_2: O-2 + O_3: O-3 + O_4: O-4 + O_5: O-5 + O_6: O-6 + O_7: O-7 + O_8: O-8 + O_9: O-9 + O_10: O-10 + W_1: W-1 + W_2: W-2 + W_3: W-3 + W_4: W-4 + W_5: W-5 + AVIATION_CADET: Aviation Cadet + CIVILIAN_EMPLOYEE: Civilian Employee + ACADEMY_CADET: Service Academy Cadet + MIDSHIPMAN: Midshipman DeptIndicator: type: string x-nullable: true @@ -1973,6 +2037,12 @@ definitions: x-nullable: true department_indicator: $ref: '#/definitions/DeptIndicator' + grade: + $ref: '#/definitions/OrderPayGrade' + origin_duty_location_id: + type: string + format: uuid + example: c56a4180-65aa-42ec-a945-5fd21dec0538 required: - service_member_id - issue_date