@dative-gpi/foundation-shared-components 0.0.177 → 0.0.178
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/components/FSDivider.vue +2 -2
- package/components/autocompletes/FSAutoCompleteAddress.vue +104 -0
- package/components/fields/FSAutocompleteField.vue +2 -1
- package/composables/useAddress.ts +113 -0
- package/package.json +5 -4
- package/plugins/index.ts +2 -1
- package/plugins/mapsPlugin.ts +37 -0
- package/shims-plugin.d.ts +3 -1
- package/shims-window.d.ts +3 -0
package/components/FSDivider.vue
CHANGED
|
@@ -68,7 +68,7 @@ export default defineComponent({
|
|
|
68
68
|
variant: {
|
|
69
69
|
type: String as PropType<"base" | "light" | "dark">,
|
|
70
70
|
required: false,
|
|
71
|
-
default: "
|
|
71
|
+
default: "base"
|
|
72
72
|
},
|
|
73
73
|
vertical: {
|
|
74
74
|
type: Boolean as PropType<boolean>,
|
|
@@ -114,4 +114,4 @@ export default defineComponent({
|
|
|
114
114
|
};
|
|
115
115
|
}
|
|
116
116
|
});
|
|
117
|
-
</script>
|
|
117
|
+
</script>
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<FSAutocompleteField
|
|
3
|
+
:clearable="false"
|
|
4
|
+
:toggleSet="false"
|
|
5
|
+
:multiple="false"
|
|
6
|
+
:items="places"
|
|
7
|
+
:modelValue="modelValuePlace"
|
|
8
|
+
@update:modelValue="onUpdate"
|
|
9
|
+
v-model:search="search"
|
|
10
|
+
v-bind="$attrs"
|
|
11
|
+
/>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script lang="ts">
|
|
15
|
+
import { defineComponent, onMounted, ref, watch } from "vue";
|
|
16
|
+
|
|
17
|
+
import { useAutocomplete } from "@dative-gpi/foundation-shared-components/composables";
|
|
18
|
+
import { useAddress } from "../../composables/useAddress";
|
|
19
|
+
|
|
20
|
+
import type { Address, Place } from "@dative-gpi/foundation-shared-domain/models";
|
|
21
|
+
|
|
22
|
+
import FSAutocompleteField from "@dative-gpi/foundation-shared-components/components/fields/FSAutocompleteField.vue";
|
|
23
|
+
|
|
24
|
+
export default defineComponent({
|
|
25
|
+
name: "FSAutocompleteAddress",
|
|
26
|
+
components: {
|
|
27
|
+
FSAutocompleteField
|
|
28
|
+
},
|
|
29
|
+
props: {
|
|
30
|
+
modelValue: {
|
|
31
|
+
type: Function as () => Address | null,
|
|
32
|
+
required: false,
|
|
33
|
+
default: null
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
emits: ["update:modelValue"],
|
|
37
|
+
setup(props, { emit }) {
|
|
38
|
+
const { search: searchAddress, get: getAddress } = useAddress();
|
|
39
|
+
|
|
40
|
+
const places = ref<Place[]>([]);
|
|
41
|
+
const modelValuePlace = ref<Place | null>(null);
|
|
42
|
+
|
|
43
|
+
const innerFetch = async (search: string | null) => {
|
|
44
|
+
if (search === null) {
|
|
45
|
+
return Promise.resolve([]);
|
|
46
|
+
}
|
|
47
|
+
places.value = await searchAddress(search);
|
|
48
|
+
return Promise.resolve([]);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const innerUpdate = async (value: { id: string; label: string; } | { id: string; label: string; }[] | null) => {
|
|
52
|
+
if (value === null) {
|
|
53
|
+
emit("update:modelValue", null);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (Array.isArray(value)) {
|
|
57
|
+
value = value[0];
|
|
58
|
+
}
|
|
59
|
+
const address = await getAddress(value);
|
|
60
|
+
emit("update:modelValue", address );
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const { search, onUpdate } = useAutocomplete(
|
|
64
|
+
places,
|
|
65
|
+
[],
|
|
66
|
+
emit,
|
|
67
|
+
innerFetch,
|
|
68
|
+
innerUpdate,
|
|
69
|
+
(item) => (item).id,
|
|
70
|
+
(item) => (item).label,
|
|
71
|
+
true,
|
|
72
|
+
false
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
const addressToPlace = (address: Address): Place => {
|
|
76
|
+
return {
|
|
77
|
+
id: address.placeId,
|
|
78
|
+
label: address.placeLabel
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
onMounted(() => {
|
|
83
|
+
if(!props.modelValue) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
modelValuePlace.value = addressToPlace(props.modelValue);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
watch(() => props.modelValue, (newValue) => {
|
|
90
|
+
if(!newValue) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
modelValuePlace.value = addressToPlace(newValue);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
modelValuePlace,
|
|
98
|
+
places,
|
|
99
|
+
search,
|
|
100
|
+
onUpdate
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
</script>
|
|
@@ -314,6 +314,7 @@ import FSRow from "../FSRow.vue";
|
|
|
314
314
|
|
|
315
315
|
export default defineComponent({
|
|
316
316
|
name: "FSAutocompleteField",
|
|
317
|
+
inheritAttrs: false,
|
|
317
318
|
components: {
|
|
318
319
|
FSSearchField,
|
|
319
320
|
FSDialogMenu,
|
|
@@ -355,7 +356,7 @@ export default defineComponent({
|
|
|
355
356
|
default: "label"
|
|
356
357
|
},
|
|
357
358
|
modelValue: {
|
|
358
|
-
type: [Array, String] as PropType<string[] | string | null>,
|
|
359
|
+
type: [Array, String, Object] as PropType<string[] | string | null | any>,
|
|
359
360
|
required: false,
|
|
360
361
|
default: null
|
|
361
362
|
},
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type { Place } from "@dative-gpi/foundation-shared-domain/models";
|
|
2
|
+
import { Address } from "@dative-gpi/foundation-shared-domain/models";
|
|
3
|
+
import _ from "lodash";
|
|
4
|
+
|
|
5
|
+
export const useAddress = () => {
|
|
6
|
+
const enabled = true;
|
|
7
|
+
let initialized = false;
|
|
8
|
+
let searchService: google.maps.places.AutocompleteService;
|
|
9
|
+
let placeService: google.maps.places.PlacesService;
|
|
10
|
+
let sessionId: google.maps.places.AutocompleteSessionToken;
|
|
11
|
+
|
|
12
|
+
const init = async () => {
|
|
13
|
+
await window.initMap;
|
|
14
|
+
searchService = new google.maps.places.AutocompleteService();
|
|
15
|
+
placeService = new google.maps.places.PlacesService(
|
|
16
|
+
document.getElementById("places") as HTMLDivElement
|
|
17
|
+
);
|
|
18
|
+
sessionId = new google.maps.places.AutocompleteSessionToken();
|
|
19
|
+
initialized = true;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
const search = async (search: string): Promise<Place[]> => {
|
|
24
|
+
if(!initialized){
|
|
25
|
+
await init();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return _search(search).then(result => {
|
|
29
|
+
return _.map(result, r => ({ id: r.place_id, label: r.description }));
|
|
30
|
+
}).catch(() => {
|
|
31
|
+
return [];
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const get = async (place: Place): Promise<Address> => {
|
|
36
|
+
if(!initialized){
|
|
37
|
+
await init();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const response = await _get(place.id);
|
|
41
|
+
sessionId = new google.maps.places.AutocompleteSessionToken();
|
|
42
|
+
if (response.address_components && response.formatted_address && response.geometry) {
|
|
43
|
+
return new Address({
|
|
44
|
+
formattedAddress: response.formatted_address,
|
|
45
|
+
locality: _find(response.address_components, "locality"),
|
|
46
|
+
country: _find(response.address_components, "country"),
|
|
47
|
+
latitude: response.geometry.location?.lat() ?? 0,
|
|
48
|
+
longitude: response.geometry.location?.lng() ?? 0,
|
|
49
|
+
|
|
50
|
+
placeId: place.id,
|
|
51
|
+
placeLabel: place.label,
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
throw new Error("missing informations");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const _search = (search: string) => {
|
|
58
|
+
if (!enabled) {
|
|
59
|
+
throw new Error("offline mode, do not call this method");
|
|
60
|
+
}
|
|
61
|
+
return new Promise<google.maps.places.AutocompletePrediction[]>(
|
|
62
|
+
(resolve, reject) => {
|
|
63
|
+
searchService!.getPlacePredictions(
|
|
64
|
+
{
|
|
65
|
+
input: search,
|
|
66
|
+
sessionToken: sessionId!
|
|
67
|
+
},
|
|
68
|
+
function (result, status) {
|
|
69
|
+
if (status != google.maps.places.PlacesServiceStatus.OK || !result) {
|
|
70
|
+
reject(status);
|
|
71
|
+
} else {
|
|
72
|
+
resolve(result);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const _get = (id: string) => {
|
|
81
|
+
if (!enabled) {
|
|
82
|
+
throw new Error("offline mode, do not call this method");
|
|
83
|
+
}
|
|
84
|
+
return new Promise<google.maps.places.PlaceResult>((resolve, reject) => {
|
|
85
|
+
placeService!.getDetails(
|
|
86
|
+
{
|
|
87
|
+
placeId: id,
|
|
88
|
+
sessionToken: sessionId!,
|
|
89
|
+
fields: ["formatted_address", "geometry", "address_components", "name"]
|
|
90
|
+
},
|
|
91
|
+
(result, status) => {
|
|
92
|
+
if (status != google.maps.places.PlacesServiceStatus.OK || !result) {
|
|
93
|
+
reject(status);
|
|
94
|
+
} else {
|
|
95
|
+
resolve(result);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const _find = (components: google.maps.GeocoderAddressComponent[], type: string): string => {
|
|
103
|
+
const found = _.find(components, c =>
|
|
104
|
+
_.some(c.types, t => t === type)
|
|
105
|
+
);
|
|
106
|
+
return (found && found.long_name) || "";
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
search,
|
|
111
|
+
get
|
|
112
|
+
}
|
|
113
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dative-gpi/foundation-shared-components",
|
|
3
3
|
"sideEffects": false,
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.178",
|
|
5
5
|
"description": "",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
"author": "",
|
|
11
11
|
"license": "ISC",
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@dative-gpi/foundation-shared-domain": "0.0.
|
|
14
|
-
"@dative-gpi/foundation-shared-services": "0.0.
|
|
13
|
+
"@dative-gpi/foundation-shared-domain": "0.0.178",
|
|
14
|
+
"@dative-gpi/foundation-shared-services": "0.0.178"
|
|
15
15
|
},
|
|
16
16
|
"peerDependencies": {
|
|
17
17
|
"@dative-gpi/bones-ui": "^0.0.75",
|
|
@@ -32,8 +32,9 @@
|
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@types/color": "3.0.6",
|
|
35
|
+
"@types/google.maps": "^3.55.10",
|
|
35
36
|
"sass": "1.71.1",
|
|
36
37
|
"sass-loader": "13.3.2"
|
|
37
38
|
},
|
|
38
|
-
"gitHead": "
|
|
39
|
+
"gitHead": "965b5f2c9bdb926c03d5a17f94991d2fc2621e51"
|
|
39
40
|
}
|
package/plugins/index.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export * from "./colorPlugin";
|
|
1
|
+
export * from "./colorPlugin";
|
|
2
|
+
export * from "./mapsPlugin";
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Plugin } from "vue";
|
|
2
|
+
|
|
3
|
+
export const MapsPlugin: Plugin = {
|
|
4
|
+
install: (_app, options: MapsOptions) => {
|
|
5
|
+
if(window?.initMap) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
const key = options?.key ?? import.meta.env.VITE_GOOGLE_MAPS_API_KEY;
|
|
9
|
+
const maps = document.createElement("script");
|
|
10
|
+
maps.setAttribute(
|
|
11
|
+
"src",
|
|
12
|
+
`https://maps.googleapis.com/maps/api/js?key=${key}&loading=async&libraries=geometry,places`
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
let resolvePromise: (value: void) => void;
|
|
16
|
+
|
|
17
|
+
const promise = new Promise<void>((resolve) => {
|
|
18
|
+
resolvePromise = resolve;
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
window.initMap = promise;
|
|
22
|
+
|
|
23
|
+
maps.onload = () => {
|
|
24
|
+
resolvePromise();
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
document.head.appendChild(maps);
|
|
28
|
+
|
|
29
|
+
const autocomplete = document.createElement("div");
|
|
30
|
+
autocomplete.id = "places";
|
|
31
|
+
document.body.appendChild(autocomplete);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface MapsOptions {
|
|
36
|
+
key?: string;
|
|
37
|
+
}
|
package/shims-plugin.d.ts
CHANGED