Skip to content

Commit 52b9007

Browse files
feat: add ability to poll for geolocation permission
1 parent d5e4f5d commit 52b9007

File tree

2 files changed

+176
-42
lines changed

2 files changed

+176
-42
lines changed

src/components/popups/sidebar/EditProfileProfile.vue

+149-41
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,18 @@ import {
4343
// PROJECT: POPUPS
4444
import { FormProfile as ProfileFormProfile } from "@/popups/sidebar/EditProfile.vue";
4545

46+
// ENUMERATIONS
47+
enum GeolocationPermission {
48+
// Not yet allowed permission.
49+
NotYetAllowed = "not-yet-allowed",
50+
// Disallowed permission.
51+
Disallowed = "disallowed",
52+
// Allowed permission.
53+
Allowed = "allowed",
54+
// Unknown permission.
55+
Unknown = "unknown"
56+
}
57+
4658
export default {
4759
name: "EditProfileProfile",
4860

@@ -64,7 +76,35 @@ export default {
6476
return {
6577
// --> DATA <--
6678

67-
fieldsets: [
79+
locationCountryOptions: countries.map(country => {
80+
return {
81+
value: country.code,
82+
label: country.name
83+
};
84+
}),
85+
86+
locationCountryIcon: {
87+
component: shallowRef(BaseFlag),
88+
89+
properties: (value: string) => {
90+
return {
91+
code: value,
92+
width: "20px",
93+
height: "15px",
94+
shadow: "none"
95+
};
96+
}
97+
},
98+
99+
// --> STATE <--
100+
101+
geolocationPermission: GeolocationPermission.Unknown
102+
};
103+
},
104+
105+
computed: {
106+
fieldsets(): Array<FormFieldset> {
107+
return [
68108
{
69109
id: "job",
70110
title: "Job information",
@@ -108,15 +148,12 @@ export default {
108148

109149
fields: [
110150
{
111-
// TODO: implement functionality using this option
112151
id: "automatic",
113152
type: FormFieldsetFieldType.Toggle,
114153
label: "Auto-detect:",
115154

116155
data: {
117-
value: {
118-
inner: false
119-
}
156+
value: this.form.locationAutodetect
120157
} as FormFieldsetFieldDataToggle
121158
},
122159

@@ -127,7 +164,8 @@ export default {
127164

128165
data: {
129166
value: this.form.locationCity,
130-
placeholder: "Enter your current city…"
167+
placeholder: "Enter your current city…",
168+
disabled: this.form.locationAutodetect.inner || false
131169
} as FormFieldsetFieldDataInput
132170
},
133171

@@ -140,25 +178,9 @@ export default {
140178
value: this.form.locationCountry,
141179
placeholder: "Pick a country…",
142180

143-
options: countries.map(country => {
144-
return {
145-
value: country.code,
146-
label: country.name
147-
};
148-
}),
149-
150-
icon: {
151-
component: shallowRef(BaseFlag),
152-
153-
properties: (value: string) => {
154-
return {
155-
code: value,
156-
width: "20px",
157-
height: "15px",
158-
shadow: "none"
159-
};
160-
}
161-
}
181+
options: this.locationCountryOptions,
182+
icon: this.locationCountryIcon,
183+
disabled: this.form.locationAutodetect.inner || false
162184
} as FormFieldsetFieldDataSelect
163185
}
164186
],
@@ -167,25 +189,34 @@ export default {
167189
{
168190
id: "location-mode",
169191
label: "Location mode:",
170-
value: "Manual", // TODO: need to geocode lat/lon to city/country
171-
icon: FormFieldsetControlIconType.LocationInactive
192+
193+
value: this.form.locationAutodetect.inner
194+
? "Automatic"
195+
: "Manual",
196+
197+
icon: this.form.locationAutodetect.inner
198+
? FormFieldsetControlIconType.LocationActive
199+
: FormFieldsetControlIconType.LocationInactive
172200
},
173201

174202
{
175203
id: "location-permission",
176204
label: "Geolocation permission:",
177-
value: "Disallowed", // TODO: from configuration
178-
179-
actions: [
180-
{
181-
type: FormFieldsetControlActionType.Button,
182-
183-
data: {
184-
text: "Manage",
185-
disabled: true
186-
} as FormFieldsetControlActionDataButton
187-
}
188-
]
205+
value: this.locationPermissionDetails.label,
206+
color: this.locationPermissionDetails.color,
207+
emphasis: this.locationPermissionDetails.emphasis,
208+
209+
actions: this.locationPermissionDetails.action
210+
? [
211+
{
212+
type: FormFieldsetControlActionType.Button,
213+
214+
data: {
215+
text: "Allow"
216+
} as FormFieldsetControlActionDataButton
217+
}
218+
]
219+
: undefined
189220
}
190221
],
191222

@@ -198,8 +229,85 @@ export default {
198229
aside: FormFieldsetOptionAside.Fixed
199230
}
200231
}
201-
] as Array<FormFieldset>
202-
};
232+
];
233+
},
234+
235+
locationPermissionDetails(): {
236+
label: string;
237+
color: string;
238+
emphasis?: boolean;
239+
action?: boolean;
240+
} {
241+
switch (this.geolocationPermission) {
242+
case GeolocationPermission.NotYetAllowed: {
243+
return {
244+
label: "Not yet allowed",
245+
color: this.form.locationAutodetect.inner ? "orange" : "grey",
246+
emphasis: this.form.locationAutodetect.inner || false
247+
// action: true -- TODO: add action
248+
};
249+
}
250+
251+
case GeolocationPermission.Disallowed: {
252+
return {
253+
label: "Disallowed",
254+
color: "red",
255+
emphasis: this.form.locationAutodetect.inner || false
256+
};
257+
}
258+
259+
case GeolocationPermission.Allowed: {
260+
return {
261+
label: "Allowed",
262+
color: this.form.locationAutodetect.inner ? "green" : "grey"
263+
};
264+
}
265+
266+
default: {
267+
return {
268+
label: "Unknown",
269+
color: "grey"
270+
};
271+
}
272+
}
273+
}
274+
},
275+
276+
async mounted() {
277+
// Check for geolocation permission
278+
this.geolocationPermission = await this.acquireGeolocationPermission();
279+
},
280+
281+
methods: {
282+
// --> HELPERS <--
283+
284+
async acquireGeolocationPermission(): Promise<GeolocationPermission> {
285+
try {
286+
// Request geolocation permission
287+
const permission = await navigator.permissions.query({
288+
name: "geolocation"
289+
});
290+
291+
// Handle acquired permission
292+
switch (permission.state) {
293+
case "granted": {
294+
return GeolocationPermission.Allowed;
295+
}
296+
297+
case "denied": {
298+
return GeolocationPermission.Disallowed;
299+
}
300+
301+
case "prompt": {
302+
return GeolocationPermission.NotYetAllowed;
303+
}
304+
}
305+
} catch (error) {
306+
this.$log.error("Failed acquiring geolocation permission", error);
307+
308+
return GeolocationPermission.Unknown;
309+
}
310+
}
203311
}
204312
};
205313
</script>

src/popups/sidebar/EditProfile.vue

+27-1
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ import { SaveAvatarRequest } from "@/broker/modules/profile";
9090

9191
// TYPES
9292
type FormValueString = { inner: string };
93+
type FormValueBoolean = { inner: boolean };
9394

9495
// INTERFACES
9596
export interface FormIdentity {
@@ -107,6 +108,7 @@ export interface FormAuthentication {
107108
export interface FormProfile {
108109
jobOrganization: FormValueString;
109110
jobTitle: FormValueString;
111+
locationAutodetect: FormValueBoolean;
110112
locationCity: FormValueString;
111113
locationCountry: FormValueString;
112114
}
@@ -189,6 +191,7 @@ export default {
189191
form: {
190192
jobOrganization: { inner: "" },
191193
jobTitle: { inner: "" },
194+
locationAutodetect: { inner: false },
192195
locationCity: { inner: "" },
193196
locationCountry: { inner: "" }
194197
} as FormProfile
@@ -250,7 +253,7 @@ export default {
250253
this.fetching = true;
251254

252255
try {
253-
await Promise.all([this.syncVCard()]);
256+
await Promise.all([this.syncStore(), this.syncVCard()]);
254257
} catch (error) {
255258
this.$log.error("Failed loading profile", error);
256259

@@ -262,6 +265,11 @@ export default {
262265
}
263266
},
264267

268+
async syncStore(): Promise<void> {
269+
// Apply store to form
270+
this.storeDataToForms();
271+
},
272+
265273
async syncVCard(): Promise<void> {
266274
// Load profile vCard (force a reload)
267275
const profile = await Store.$profile.loadUserProfile(this.selfJID, true);
@@ -270,6 +278,14 @@ export default {
270278
this.vCardDataToForms(profile);
271279
},
272280

281+
storeDataToForms(): void {
282+
const formProfile = this.contentSections.profile.properties.form;
283+
284+
// Populate profile form
285+
formProfile.locationAutodetect.inner =
286+
Store.$settings.profile.location.autodetect || false;
287+
},
288+
273289
vCardDataToForms(profile: ProfileEntry): void {
274290
const formIdentity = this.contentSections.identity.properties.form,
275291
formProfile = this.contentSections.profile.properties.form;
@@ -294,6 +310,13 @@ export default {
294310
profile.information?.location?.country || "";
295311
},
296312

313+
formsToStoreApply(formProfile: FormProfile): void {
314+
// Save profile
315+
Store.$settings.setProfileLocationAutodetect(
316+
formProfile.locationAutodetect.inner
317+
);
318+
},
319+
297320
formsToUserProfile(
298321
formIdentity: FormIdentity,
299322
formProfile: FormProfile
@@ -354,6 +377,9 @@ export default {
354377
if (this.fetching !== true && this.saving !== true) {
355378
this.saving = true;
356379

380+
// Apply forms in store
381+
this.formsToStoreApply(this.contentSections.profile.properties.form);
382+
357383
// Generate vCard save data
358384
const vCardData = this.formsToUserProfile(
359385
this.contentSections.identity.properties.form,

0 commit comments

Comments
 (0)