@bash-app/bash-common 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bash-app/bash-common",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Common data and scripts to use on the frontend and backend",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
package/src/index.ts CHANGED
@@ -3,3 +3,4 @@ export * from "./definitions";
3
3
  export * from "./utils/ticketListUtils";
4
4
  export * from "./utils/dateTimeUtils";
5
5
  export * from "./utils/recurrenceUtils";
6
+ export * from "./utils/addressUtils";
@@ -0,0 +1,173 @@
1
+
2
+ const ADDRESS_DELIM = '|';
3
+
4
+ const googleMapsApiKey = process.env.REACT_APP_GOOGLE_MAP_API_KEY as string;
5
+
6
+
7
+ export interface IAddress {
8
+ place: string;
9
+ street: string;
10
+ city: string;
11
+ state: string;
12
+ zipCode: string;
13
+ country: string;
14
+ }
15
+
16
+ export function addressHasEnoughDataForGeolocation(address: IAddress): boolean {
17
+ return !!((address.place && address.city && address.state) || (address.street && address.city && address.state));
18
+ }
19
+
20
+ export function addressValuesToDatabaseAddressString(addressValues: IAddress): string {
21
+ const { place = '', street, city, state, zipCode, country } = addressValues;
22
+ return [place, street, city, state, zipCode, country].join(ADDRESS_DELIM);
23
+ }
24
+
25
+ export function databaseAddressStringToAddressValues(addressString: string | undefined | null): IAddress {
26
+ if (addressString) {
27
+ const addressArray = addressString.split(ADDRESS_DELIM);
28
+ return {
29
+ place: addressArray[0],
30
+ street: addressArray[1],
31
+ city: addressArray[2],
32
+ state: addressArray[3],
33
+ zipCode: addressArray[4],
34
+ country: 'USA'
35
+ }
36
+ }
37
+ return { place: '', street: '', city: '', state: '', zipCode: '', country: '' };
38
+ }
39
+
40
+
41
+ export function databaseAddressStringToOneLineString(addressString: string | undefined | null): string {
42
+ if (addressString) {
43
+ const address = databaseAddressStringToAddressValues(addressString);
44
+ let addressArr = address.place ? [address.place] : [];
45
+ addressArr = [...addressArr, address.street, address.city, address.state];
46
+ const addressStr = addressArr.filter((str) => !!str).join(', ');
47
+ return `${addressStr} ${address.zipCode}`;
48
+ }
49
+ return '';
50
+ }
51
+
52
+ export function databaseAddressStringToDisplayString(addressString: string | undefined | null): string {
53
+ if (addressString) {
54
+ const oneLineString = databaseAddressStringToOneLineString(addressString);
55
+ const formatted = oneLineString.replace(/([A-Z])(?=[A-Z][a-z])/g, "$1 ") // Add space between a single uppercase letter and a capitalized word
56
+ .replace(/(\d)(?=[A-Z])/g, "$1 ") // Add space between numbers and letters
57
+ .replace(/,/g, ", "); // Add space after commas
58
+ return formatted;
59
+ }
60
+ return '';
61
+ }
62
+
63
+
64
+ export async function getAddressFromCoordinates( lat: number, lng: number ): Promise<IAddress> {
65
+ const apiUrl = `https://maps.googleapis.com/maps/api/geocode/json?latlng=${lat},${lng}&key=${googleMapsApiKey}&loading=async`;
66
+ try {
67
+ const response = await fetch(apiUrl);
68
+ const data = await response.json();
69
+ if (data.results.length > 0) {
70
+ const addressComponents = data.results[0].address_components;
71
+
72
+ let street = "";
73
+ let city = "";
74
+ let state = "";
75
+ let zipCode = "";
76
+
77
+ addressComponents.forEach((component: any) => {
78
+ if (component.types.includes("route")) {
79
+ street = component.long_name;
80
+ } else if (component.types.includes("locality")) {
81
+ city = component.long_name;
82
+ } else if (component.types.includes("administrative_area_level_1")) {
83
+ state = component.short_name;
84
+ } else if (component.types.includes("postal_code")) {
85
+ zipCode = component.long_name;
86
+ }
87
+ });
88
+
89
+ return { place: '', street, city, state, zipCode, country: 'USA' };
90
+ } else {
91
+ throw new Error("No address found");
92
+ }
93
+ } catch (error) {
94
+ console.error(error);
95
+ return {
96
+ place: '',
97
+ street: "",
98
+ city: "",
99
+ state: "",
100
+ zipCode: "",
101
+ country: 'USA'
102
+ };
103
+ }
104
+ }
105
+
106
+ export function extractAddressComponents(place: any): IAddress {
107
+ const addressComponents = place.address_components;
108
+ let streetNumber = '';
109
+ let streetName = '';
110
+ let city = '';
111
+ let state = '';
112
+ let zipCode = '';
113
+ let country = 'USA';
114
+
115
+ addressComponents.forEach((component: any) => {
116
+ const types = component.types;
117
+ if (types.includes('street_number')) {
118
+ streetNumber = component.long_name;
119
+ }
120
+ if (types.includes('route')) {
121
+ streetName = component.long_name;
122
+ }
123
+ if (types.includes('locality')) {
124
+ city = component.long_name;
125
+ }
126
+ if (types.includes('administrative_area_level_1')) {
127
+ state = component.short_name;
128
+ }
129
+ if (types.includes('postal_code')) {
130
+ zipCode = component.long_name;
131
+ }
132
+ if (types.includes('country')) {
133
+ country = component.long_name;
134
+ }
135
+ });
136
+
137
+ const street = `${streetNumber} ${streetName}`.trim();
138
+
139
+ return {
140
+ place: place.name || '',
141
+ street,
142
+ city,
143
+ state,
144
+ zipCode,
145
+ country
146
+ };
147
+ }
148
+
149
+
150
+ export async function getGeoCoordinatesFromAddress(address: IAddress): Promise<{lat: number, lng: number} | undefined> {
151
+ const addressStr = `${address.street}, ${address.city}, ${address.state} ${address.zipCode}, ${address.country}`;
152
+
153
+ const response = await fetch(
154
+ `https://maps.googleapis.com/maps/api/geocode/json?address=${encodeURIComponent(addressStr)}&key=${googleMapsApiKey}`
155
+ );
156
+ if (!response.ok) {
157
+ console.error('Geocode response was not ok for address: ' + addressStr);
158
+ }
159
+
160
+ const data = await response.json();
161
+
162
+ if (data.status === 'OK') {
163
+ if (data.results?.length) {
164
+ return data.results[0].geometry.location;
165
+ }
166
+ else {
167
+ console.error('Geocode results were empty with address: ' + addressStr);
168
+ }
169
+ }
170
+ else {
171
+ console.error(`Geocode was not successful with address: ${addressStr}\nfor the following reason: ${data.status}`);
172
+ }
173
+ }