-
Notifications
You must be signed in to change notification settings - Fork 54
/
facilitySchema.ts
170 lines (154 loc) · 4.63 KB
/
facilitySchema.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
import * as yup from "yup";
import { PhoneNumberUtil } from "google-libphonenumber";
import { liveJurisdictions } from "../../../config/constants";
import {
isValidCLIANumber,
stateRequiresCLIANumberValidation,
} from "../../utils/clia";
import { isEmptyString } from "../../utils";
const phoneUtil = PhoneNumberUtil.getInstance();
type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
export type RequiredFacilityFields = PartialBy<
Facility,
"id" | "email" | "streetTwo" | "city" | "orderingProvider"
>;
function orderingProviderIsRequired(
this: yup.TestContext<Record<string, any>>,
input = ""
): boolean {
if (this?.options?.context?.orderingProviderIsRequired) {
return !isEmptyString(input);
}
return true;
}
function isValidNpi(
this: yup.TestContext<Record<string, any>>,
input = ""
): boolean {
if (this?.options?.context?.orderingProviderIsRequired) {
let npiValidator = /^\d{1,10}$/;
return npiValidator.test(input);
}
return true;
}
type RequiredProviderFields = Nullable<Partial<Provider>>;
const orderingProviderFormatError = (field: string) =>
field === "NPI"
? "NPI should be a 10-digit numerical value (##########)"
: `Ordering provider ${field} is incorrectly formatted`;
const providerSchema: yup.SchemaOf<RequiredProviderFields> = yup.object({
firstName: yup
.string()
.test(
"ordering-provider-first-name",
orderingProviderFormatError("first name"),
orderingProviderIsRequired
),
middleName: yup.string().nullable(),
lastName: yup
.string()
.test(
"ordering-provider-last-name",
orderingProviderFormatError("last name"),
orderingProviderIsRequired
),
suffix: yup.string().nullable(),
NPI: yup
.string()
.test(
"ordering-provider-npi",
orderingProviderFormatError("NPI"),
isValidNpi
),
phone: yup
.string()
.test(
"ordering-provider-phone",
orderingProviderFormatError("phone"),
orderingProviderIsRequired
),
street: yup.string().nullable(),
streetTwo: yup.string().nullable(),
city: yup.string().nullable(),
state: yup.string().nullable(),
zipCode: yup.string().nullable(),
});
const deviceTypeSchema: yup.SchemaOf<FacilityFormDeviceType> = yup.object({
internalId: yup.string().required(),
name: yup.string().required(),
testLength: yup.number().optional(),
});
export const facilitySchema: yup.SchemaOf<RequiredFacilityFields> = yup.object({
name: yup.string().required("Facility name is missing"),
cliaNumber: yup
.string()
.required()
.test(
"facility-clia",
"CLIA numbers must be 10 characters (##D#######), or a special temporary number from CA, IL, VT, WA, WY, or the Department of Defense",
(input, facility) => {
if (!stateRequiresCLIANumberValidation(facility.parent.state)) {
return true;
}
if (!input) {
return false;
}
return isValidCLIANumber(input, facility.parent.state);
}
),
street: yup.string().required("Facility street is missing"),
zipCode: yup.string().required("Facility zip code is missing"),
deviceTypes: yup
.array()
.of(deviceTypeSchema)
.min(1, "There must be at least one device")
.required("There must be at least one device"),
orderingProvider: providerSchema.nullable(),
phone: yup
.string()
.test(
"facility-phone",
"Facility phone number is missing or invalid",
function (input) {
if (!input) {
return false;
}
try {
const number = phoneUtil.parseAndKeepRawInput(input, "US");
return phoneUtil.isValidNumber(number);
} catch (e: any) {
return false;
}
}
)
.required("Facility phone number is missing or invalid"),
state: yup
.string()
.test("facility-state", "Facility state is missing", function (input) {
if (!input) {
return false;
}
return liveJurisdictions.includes(input);
})
.required("Facility state is missing"),
id: yup.string(),
email: yup.string().email("Email is incorrectly formatted").nullable(),
streetTwo: yup.string().nullable(),
city: yup.string().nullable(),
});
type FacilityErrorKeys =
| keyof Facility
| "orderingProvider.firstName"
| "orderingProvider.middleName"
| "orderingProvider.lastName"
| "orderingProvider.suffix"
| "orderingProvider.NPI"
| "orderingProvider.phone"
| "orderingProvider.street"
| "orderingProvider.streetTwo"
| "orderingProvider.city"
| "orderingProvider.state"
| "orderingProvider.zipCode";
export type FacilityErrors = Partial<
Record<FacilityErrorKeys, React.ReactNode>
>;