@live-change/user-frontend 0.8.63 → 0.8.65
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/.nx/cache/file-map.json +74 -42
- package/.nx/cache/nx_files.nxt +0 -0
- package/front/public/images/flag_placeholder.png +0 -0
- package/front/public/images/flags_responsive.png +0 -0
- package/front/src/connected/ConnectEmail.vue +1 -1
- package/front/src/connected/ConnectPhone.vue +5 -4
- package/front/src/connected/Connected.vue +8 -41
- package/front/src/connected/connected.js +89 -0
- package/front/src/connected/routes.js +3 -0
- package/front/src/identification/UserIdentification.vue +3 -0
- package/front/src/nav/UserIcon.vue +1 -1
- package/front/src/phone/PhoneInput.vue +107 -0
- package/front/src/sign/LinkedinAuth.vue +96 -0
- package/front/src/sign/LinkedinAuthReturn.vue +105 -0
- package/front/src/sign/SignInEmail.vue +8 -0
- package/front/src/sign/routes.js +8 -0
- package/front/src/utils/flags.scss +973 -0
- package/front/src/utils/linkedinAuth.js +29 -0
- package/index.js +2 -0
- package/package.json +26 -26
- package/server/app.config.js +9 -1
- package/server/services.list.js +4 -0
package/.nx/cache/file-map.json
CHANGED
|
@@ -2,29 +2,29 @@
|
|
|
2
2
|
"version": "6.0",
|
|
3
3
|
"nxVersion": "18.0.6",
|
|
4
4
|
"deps": {
|
|
5
|
-
"@live-change/cli": "0.8.
|
|
6
|
-
"@live-change/dao": "0.8.
|
|
7
|
-
"@live-change/dao-vue3": "0.8.
|
|
8
|
-
"@live-change/dao-websocket": "0.8.
|
|
9
|
-
"@live-change/email-service": "0.8.
|
|
10
|
-
"@live-change/framework": "0.8.
|
|
11
|
-
"@live-change/identicon-service": "0.8.
|
|
12
|
-
"@live-change/image-frontend": "0.8.
|
|
13
|
-
"@live-change/message-authentication-service": "0.8.
|
|
14
|
-
"@live-change/notification-service": "0.8.
|
|
15
|
-
"@live-change/password-authentication-service": "0.8.
|
|
16
|
-
"@live-change/pattern": "0.8.
|
|
17
|
-
"@live-change/secret-code-service": "0.8.
|
|
18
|
-
"@live-change/secret-link-service": "0.8.
|
|
19
|
-
"@live-change/security-frontend": "0.8.
|
|
20
|
-
"@live-change/security-service": "0.8.
|
|
21
|
-
"@live-change/session-service": "0.8.
|
|
22
|
-
"@live-change/timer-service": "0.8.
|
|
23
|
-
"@live-change/upload-service": "0.8.
|
|
24
|
-
"@live-change/user-identification-service": "0.8.
|
|
25
|
-
"@live-change/user-service": "0.8.
|
|
26
|
-
"@live-change/vue3-components": "0.8.
|
|
27
|
-
"@live-change/vue3-ssr": "0.8.
|
|
5
|
+
"@live-change/cli": "0.8.64",
|
|
6
|
+
"@live-change/dao": "0.8.64",
|
|
7
|
+
"@live-change/dao-vue3": "0.8.64",
|
|
8
|
+
"@live-change/dao-websocket": "0.8.64",
|
|
9
|
+
"@live-change/email-service": "0.8.64",
|
|
10
|
+
"@live-change/framework": "0.8.64",
|
|
11
|
+
"@live-change/identicon-service": "0.8.64",
|
|
12
|
+
"@live-change/image-frontend": "0.8.64",
|
|
13
|
+
"@live-change/message-authentication-service": "0.8.64",
|
|
14
|
+
"@live-change/notification-service": "0.8.64",
|
|
15
|
+
"@live-change/password-authentication-service": "0.8.64",
|
|
16
|
+
"@live-change/pattern": "0.8.64",
|
|
17
|
+
"@live-change/secret-code-service": "0.8.64",
|
|
18
|
+
"@live-change/secret-link-service": "0.8.64",
|
|
19
|
+
"@live-change/security-frontend": "0.8.64",
|
|
20
|
+
"@live-change/security-service": "0.8.64",
|
|
21
|
+
"@live-change/session-service": "0.8.64",
|
|
22
|
+
"@live-change/timer-service": "0.8.64",
|
|
23
|
+
"@live-change/upload-service": "0.8.64",
|
|
24
|
+
"@live-change/user-identification-service": "0.8.64",
|
|
25
|
+
"@live-change/user-service": "0.8.64",
|
|
26
|
+
"@live-change/vue3-components": "0.8.64",
|
|
27
|
+
"@live-change/vue3-ssr": "0.8.64",
|
|
28
28
|
"@vueuse/core": "^10.11.0",
|
|
29
29
|
"codeceptjs-assert": "^0.0.5",
|
|
30
30
|
"codeceptjs-video-helper": "0.1.3",
|
|
@@ -43,13 +43,13 @@
|
|
|
43
43
|
"vue-router": "^4.3.3",
|
|
44
44
|
"vue3-scroll-border": "0.1.6",
|
|
45
45
|
"wtfnode": "^0.9.1",
|
|
46
|
-
"@live-change/codeceptjs-helper": "0.8.
|
|
47
|
-
"codeceptjs": "^3.5
|
|
46
|
+
"@live-change/codeceptjs-helper": "0.8.64",
|
|
47
|
+
"codeceptjs": "^3.6.5",
|
|
48
48
|
"generate-password": "1.7.1",
|
|
49
49
|
"playwright": "^1.41.2",
|
|
50
50
|
"random-profile-generator": "^2.3.0",
|
|
51
51
|
"txtgen": "^3.0.6",
|
|
52
|
-
"webdriverio": "^8.
|
|
52
|
+
"webdriverio": "^8.40.2"
|
|
53
53
|
},
|
|
54
54
|
"pathMappings": {},
|
|
55
55
|
"nxJsonPlugins": [],
|
|
@@ -60,9 +60,13 @@
|
|
|
60
60
|
"file": ".gitignore",
|
|
61
61
|
"hash": "16223102139109646162"
|
|
62
62
|
},
|
|
63
|
+
{
|
|
64
|
+
"file": "LICENSE",
|
|
65
|
+
"hash": "10221119794387200971"
|
|
66
|
+
},
|
|
63
67
|
{
|
|
64
68
|
"file": "e2e/codecept.conf.js",
|
|
65
|
-
"hash": "
|
|
69
|
+
"hash": "13791327886840311692"
|
|
66
70
|
},
|
|
67
71
|
{
|
|
68
72
|
"file": "e2e/connectEmailCode.test.js",
|
|
@@ -178,11 +182,15 @@
|
|
|
178
182
|
},
|
|
179
183
|
{
|
|
180
184
|
"file": "front/src/connected/Connected.vue",
|
|
181
|
-
"hash": "
|
|
185
|
+
"hash": "11506706671292138762"
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"file": "front/src/connected/connected.js",
|
|
189
|
+
"hash": "17119205448655692635"
|
|
182
190
|
},
|
|
183
191
|
{
|
|
184
192
|
"file": "front/src/connected/routes.js",
|
|
185
|
-
"hash": "
|
|
193
|
+
"hash": "2551528109489035833"
|
|
186
194
|
},
|
|
187
195
|
{
|
|
188
196
|
"file": "front/src/delete/Delete.vue",
|
|
@@ -208,6 +216,18 @@
|
|
|
208
216
|
"file": "front/src/entry-server.js",
|
|
209
217
|
"hash": "3852150522654880349"
|
|
210
218
|
},
|
|
219
|
+
{
|
|
220
|
+
"file": "front/src/google-access/GoogleAccess.vue",
|
|
221
|
+
"hash": "9529831848748475095"
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
"file": "front/src/google-access/GoogleAccessGained.vue",
|
|
225
|
+
"hash": "4309063406044103630"
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
"file": "front/src/google-access/routes.js",
|
|
229
|
+
"hash": "6244550399322220890"
|
|
230
|
+
},
|
|
211
231
|
{
|
|
212
232
|
"file": "front/src/identification/IdentificationSettings.vue",
|
|
213
233
|
"hash": "15002414951607988030"
|
|
@@ -218,7 +238,7 @@
|
|
|
218
238
|
},
|
|
219
239
|
{
|
|
220
240
|
"file": "front/src/identification/UserIdentification.vue",
|
|
221
|
-
"hash": "
|
|
241
|
+
"hash": "12949250406055003638"
|
|
222
242
|
},
|
|
223
243
|
{
|
|
224
244
|
"file": "front/src/identification/routes.js",
|
|
@@ -278,7 +298,7 @@
|
|
|
278
298
|
},
|
|
279
299
|
{
|
|
280
300
|
"file": "front/src/nav/UserIcon.vue",
|
|
281
|
-
"hash": "
|
|
301
|
+
"hash": "3324270693059299280"
|
|
282
302
|
},
|
|
283
303
|
{
|
|
284
304
|
"file": "front/src/nav/UserMenu.vue",
|
|
@@ -354,7 +374,7 @@
|
|
|
354
374
|
},
|
|
355
375
|
{
|
|
356
376
|
"file": "front/src/router.js",
|
|
357
|
-
"hash": "
|
|
377
|
+
"hash": "6232756401755977821"
|
|
358
378
|
},
|
|
359
379
|
{
|
|
360
380
|
"file": "front/src/settings/Settings.vue",
|
|
@@ -374,19 +394,27 @@
|
|
|
374
394
|
},
|
|
375
395
|
{
|
|
376
396
|
"file": "front/src/sign/GoogleAuth.vue",
|
|
377
|
-
"hash": "
|
|
397
|
+
"hash": "17904987660087619857"
|
|
378
398
|
},
|
|
379
399
|
{
|
|
380
400
|
"file": "front/src/sign/GoogleAuthReturn.vue",
|
|
381
|
-
"hash": "
|
|
401
|
+
"hash": "11166765015834314072"
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
"file": "front/src/sign/LinkedinAuth.vue",
|
|
405
|
+
"hash": "9567465782490495596"
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
"file": "front/src/sign/LinkedinAuthReturn.vue",
|
|
409
|
+
"hash": "9428875039032707697"
|
|
382
410
|
},
|
|
383
411
|
{
|
|
384
412
|
"file": "front/src/sign/SignInEmail.vue",
|
|
385
|
-
"hash": "
|
|
413
|
+
"hash": "15480628897033099010"
|
|
386
414
|
},
|
|
387
415
|
{
|
|
388
416
|
"file": "front/src/sign/SignInFinished.vue",
|
|
389
|
-
"hash": "
|
|
417
|
+
"hash": "11444495191715209127"
|
|
390
418
|
},
|
|
391
419
|
{
|
|
392
420
|
"file": "front/src/sign/SignOut.vue",
|
|
@@ -402,11 +430,11 @@
|
|
|
402
430
|
},
|
|
403
431
|
{
|
|
404
432
|
"file": "front/src/sign/SignUpFinished.vue",
|
|
405
|
-
"hash": "
|
|
433
|
+
"hash": "4534581805740174218"
|
|
406
434
|
},
|
|
407
435
|
{
|
|
408
436
|
"file": "front/src/sign/routes.js",
|
|
409
|
-
"hash": "
|
|
437
|
+
"hash": "1023097621604756838"
|
|
410
438
|
},
|
|
411
439
|
{
|
|
412
440
|
"file": "front/src/utils/countries.js",
|
|
@@ -416,21 +444,25 @@
|
|
|
416
444
|
"file": "front/src/utils/googleAuth.js",
|
|
417
445
|
"hash": "10682927559112869908"
|
|
418
446
|
},
|
|
447
|
+
{
|
|
448
|
+
"file": "front/src/utils/linkedinAuth.js",
|
|
449
|
+
"hash": "16435105867959168771"
|
|
450
|
+
},
|
|
419
451
|
{
|
|
420
452
|
"file": "front/vite.config.js",
|
|
421
453
|
"hash": "4207480426880236517"
|
|
422
454
|
},
|
|
423
455
|
{
|
|
424
456
|
"file": "index.js",
|
|
425
|
-
"hash": "
|
|
457
|
+
"hash": "16467025442967385199"
|
|
426
458
|
},
|
|
427
459
|
{
|
|
428
460
|
"file": "package.json",
|
|
429
|
-
"hash": "
|
|
461
|
+
"hash": "4875568356135693252"
|
|
430
462
|
},
|
|
431
463
|
{
|
|
432
464
|
"file": "server/app.config.js",
|
|
433
|
-
"hash": "
|
|
465
|
+
"hash": "14052619601583710778"
|
|
434
466
|
},
|
|
435
467
|
{
|
|
436
468
|
"file": "server/init-functions.js",
|
|
@@ -446,7 +478,7 @@
|
|
|
446
478
|
},
|
|
447
479
|
{
|
|
448
480
|
"file": "server/services.list.js",
|
|
449
|
-
"hash": "
|
|
481
|
+
"hash": "2018796374883415113"
|
|
450
482
|
},
|
|
451
483
|
{
|
|
452
484
|
"file": "server/start.js",
|
package/.nx/cache/nx_files.nxt
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
</Divider>
|
|
26
26
|
|
|
27
27
|
<router-link :to="{ name: 'user:connect-phone' }">
|
|
28
|
-
<Button label="Add Phone" icon="pi pi-
|
|
28
|
+
<Button label="Add Phone" icon="pi pi-mobile" class="w-full p-button-secondary mb-2" />
|
|
29
29
|
</router-link>
|
|
30
30
|
|
|
31
31
|
<!-- <Button label="Connect GitHub account" icon="pi pi-github" class="w-full p-button-secondary mb-2"></Button>
|
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
<label for="email" class="block text-900 font-medium mb-2">
|
|
13
13
|
Phone number
|
|
14
14
|
</label>
|
|
15
|
-
<
|
|
16
|
-
aria-describedby="
|
|
15
|
+
<PhoneInput id="phone" class="w-full"
|
|
16
|
+
aria-describedby="phone-help" :class="{ 'p-invalid': data.phoneError }"
|
|
17
17
|
v-model="data.phone" />
|
|
18
|
-
<small v-if="data.phoneError" id="
|
|
18
|
+
<small v-if="data.phoneError" id="phone-help" class="p-error">{{ data.phoneError }}</small>
|
|
19
19
|
</div>
|
|
20
20
|
|
|
21
21
|
<Button label="Add Phone" icon="pi pi-mobile" class="w-full" type="submit" />
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
</Divider>
|
|
26
26
|
|
|
27
27
|
<router-link :to="{ name: 'user:connect-email' }">
|
|
28
|
-
<Button label="Add Email" icon="pi pi-
|
|
28
|
+
<Button label="Add Email" icon="pi pi-envelope" class="w-full p-button-secondary mb-2" />
|
|
29
29
|
</router-link>
|
|
30
30
|
|
|
31
31
|
<!-- <Button label="Connect GitHub account" icon="pi pi-github" class="w-full p-button-secondary mb-2"></Button>-->
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
import Checkbox from "primevue/checkbox"
|
|
42
42
|
import Button from "primevue/button"
|
|
43
43
|
import Divider from "primevue/divider"
|
|
44
|
+
import PhoneInput from "../phone/PhoneInput.vue"
|
|
44
45
|
|
|
45
46
|
import { useRouter } from 'vue-router'
|
|
46
47
|
const router = useRouter()
|
|
@@ -27,6 +27,11 @@
|
|
|
27
27
|
<i class="pi pi-google mr-2"></i>
|
|
28
28
|
<span class="block text-900 font-medium text-lg">{{ account.email }}</span>
|
|
29
29
|
</div>
|
|
30
|
+
<div v-if="account.accountType.accountType === 'linkedin'"
|
|
31
|
+
class="flex flex-row align-items-center">
|
|
32
|
+
<i class="pi pi-linkedin mr-2"></i>
|
|
33
|
+
<span class="block text-900 font-medium text-lg">{{ account.name }}</span>
|
|
34
|
+
</div>
|
|
30
35
|
<pre v-else>{{ account }}</pre>
|
|
31
36
|
<Button class="p-button-text p-button-plain p-button-rounded mr-1" icon="pi pi-times"
|
|
32
37
|
v-if="canDelete"
|
|
@@ -70,11 +75,6 @@
|
|
|
70
75
|
import { useApi, live, usePath, useActions } from '@live-change/vue3-ssr'
|
|
71
76
|
const api = useApi()
|
|
72
77
|
const path = usePath()
|
|
73
|
-
const messageAuthenticationClientConfig = api.getServiceDefinition('messageAuthentication')?.clientConfig
|
|
74
|
-
const contactTypesAvailable = messageAuthenticationClientConfig?.contactTypes || []
|
|
75
|
-
|
|
76
|
-
const userClientConfig = api.getServiceDefinition('user')?.clientConfig
|
|
77
|
-
const accountTypesAvailable = userClientConfig?.remoteAccountTypes || []
|
|
78
78
|
|
|
79
79
|
const messageAuthenticationApi = useActions().messageAuthentication
|
|
80
80
|
|
|
@@ -118,43 +118,10 @@
|
|
|
118
118
|
})
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
|
|
122
|
-
const contactTypeUpper = contactType[0].toUpperCase() + contactType.slice(1)
|
|
123
|
-
|
|
124
|
-
let serviceName = contactType
|
|
125
|
-
let viewName = 'myUser'+contactTypeUpper+'s'
|
|
126
|
-
if(!path[serviceName]) { // find service by viewName
|
|
127
|
-
for(const s in path) {
|
|
128
|
-
if(path[s][viewName]) {
|
|
129
|
-
serviceName = s
|
|
130
|
-
break
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
//console.log('contactType', contactType, 'serviceName', serviceName, 'viewName', viewName)
|
|
135
|
-
console.log(`path[${serviceName}][${viewName}] =`, path[serviceName][viewName])
|
|
136
|
-
return {
|
|
137
|
-
contactType,
|
|
138
|
-
serviceName,
|
|
139
|
-
viewName,
|
|
140
|
-
path: path[serviceName][viewName]({}),
|
|
141
|
-
contacts: null
|
|
142
|
-
}
|
|
143
|
-
})
|
|
121
|
+
import { getContactTypes, getAccountTypes} from './connected.js'
|
|
144
122
|
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
let viewName = 'myUserAccounts'
|
|
148
|
-
console.log('remoteAccountType', accountType, 'serviceName', serviceName, 'viewName', viewName)
|
|
149
|
-
console.log(`path[${serviceName}][${viewName}] =`, path[serviceName][viewName])
|
|
150
|
-
return {
|
|
151
|
-
accountType,
|
|
152
|
-
serviceName,
|
|
153
|
-
viewName,
|
|
154
|
-
path: path[serviceName][viewName]({}),
|
|
155
|
-
accounts: null
|
|
156
|
-
}
|
|
157
|
-
})
|
|
123
|
+
const contactsTypes = getContactTypes()
|
|
124
|
+
const accountTypes = getAccountTypes()
|
|
158
125
|
|
|
159
126
|
const contactPromises = contactsTypes.map(async contactType => {
|
|
160
127
|
contactType.contacts = await live(contactType.path)
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { useApi, live } from '@live-change/vue3-ssr'
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
|
|
4
|
+
export function getContactTypes(api = useApi()) {
|
|
5
|
+
const path = api.fetch
|
|
6
|
+
const messageAuthenticationClientConfig = api.getServiceDefinition('messageAuthentication')?.clientConfig
|
|
7
|
+
const contactTypesAvailable = messageAuthenticationClientConfig?.contactTypes || []
|
|
8
|
+
const contactsTypes = contactTypesAvailable.map(contactType => {
|
|
9
|
+
const contactTypeUpper = contactType[0].toUpperCase() + contactType.slice(1)
|
|
10
|
+
|
|
11
|
+
let serviceName = contactType
|
|
12
|
+
let viewName = 'myUser'+contactTypeUpper+'s'
|
|
13
|
+
if(!path[serviceName]) { // find service by viewName
|
|
14
|
+
for(const s in path) {
|
|
15
|
+
if(path[s][viewName]) {
|
|
16
|
+
serviceName = s
|
|
17
|
+
break
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
//console.log('contactType', contactType, 'serviceName', serviceName, 'viewName', viewName)
|
|
22
|
+
console.log(`path[${serviceName}][${viewName}] =`, path[serviceName][viewName])
|
|
23
|
+
return {
|
|
24
|
+
contactType,
|
|
25
|
+
serviceName,
|
|
26
|
+
viewName,
|
|
27
|
+
path: path[serviceName][viewName]({}),
|
|
28
|
+
contacts: null,
|
|
29
|
+
async fetchContacts(context, onUnmountedCb){
|
|
30
|
+
const contacts = await live(path[serviceName][viewName]({}), context, onUnmountedCb)
|
|
31
|
+
this.contacts = contacts
|
|
32
|
+
return contacts
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
return contactsTypes
|
|
37
|
+
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function getAccountTypes(api = useApi()) {
|
|
41
|
+
const userClientConfig = api.getServiceDefinition('user')?.clientConfig
|
|
42
|
+
const accountTypesAvailable = userClientConfig?.remoteAccountTypes || []
|
|
43
|
+
const path = api.fetch
|
|
44
|
+
const accountTypes = accountTypesAvailable.map(accountType => {
|
|
45
|
+
let serviceName = accountType+'Authentication'
|
|
46
|
+
let viewName = 'myUserAccounts'
|
|
47
|
+
console.log('remoteAccountType', accountType, 'serviceName', serviceName, 'viewName', viewName)
|
|
48
|
+
console.log(`path[${serviceName}][${viewName}] =`, path[serviceName][viewName])
|
|
49
|
+
return {
|
|
50
|
+
accountType,
|
|
51
|
+
serviceName,
|
|
52
|
+
viewName,
|
|
53
|
+
path: path[serviceName][viewName]({}),
|
|
54
|
+
accounts: null,
|
|
55
|
+
async fetchAccounts(context, onUnmountedCb){
|
|
56
|
+
const accounts = await live(path[serviceName][viewName]({}), context, onUnmountedCb)
|
|
57
|
+
this.accounts = accounts
|
|
58
|
+
return accounts
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
return accountTypes
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export async function getContacts(api = useApi()) {
|
|
66
|
+
const contactsTypes = getContactTypes(api)
|
|
67
|
+
for(const contactType of contactsTypes) {
|
|
68
|
+
await contactType.fetchContacts()
|
|
69
|
+
}
|
|
70
|
+
const contacts = computed(() => contactsTypes.map((c,i) => c.contacts.value.map(v => ({
|
|
71
|
+
contactType: c.contactType,
|
|
72
|
+
serviceName: c.serviceName,
|
|
73
|
+
...(v)
|
|
74
|
+
}))).flat())
|
|
75
|
+
return contacts
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export async function getAccounts(api = useApi()) {
|
|
79
|
+
const accountTypes = getAccountTypes(api)
|
|
80
|
+
for(const accountType of accountTypes) {
|
|
81
|
+
await accountType.fetchAccounts()
|
|
82
|
+
}
|
|
83
|
+
const accounts = computed(() => accountTypes.map((c,i) => c.accounts.value.map(v => ({
|
|
84
|
+
accountType: c.contactType,
|
|
85
|
+
serviceName: c.serviceName,
|
|
86
|
+
...(v)
|
|
87
|
+
}))).flat())
|
|
88
|
+
return accounts
|
|
89
|
+
}
|
|
@@ -15,6 +15,9 @@ export function routes(config = {}) {
|
|
|
15
15
|
route({ name: 'user:connect-google', path: prefix + 'connect-google',
|
|
16
16
|
redirect: { name: 'user:googleAuth', params: { action: 'connectGoogle' } } }),
|
|
17
17
|
|
|
18
|
+
route({ name: 'user:connect-linkedin', path: prefix + 'connect-linkedin',
|
|
19
|
+
redirect: { name: 'user:linkedinAuth', params: { action: 'connectLinkedin' } } }),
|
|
20
|
+
|
|
18
21
|
route({ name: 'user:connectFinished', path: prefix + 'connect-finished',
|
|
19
22
|
component: () => import("./ConnectFinished.vue") }),
|
|
20
23
|
|
|
@@ -100,6 +100,9 @@
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
const name = computed(() => userData.value?.name
|
|
103
|
+
|| (userData.value.firstName && userData.value.lastName
|
|
104
|
+
? userData.value.firstName + ' ' + userData.value.lastName
|
|
105
|
+
: userData.value.firstName)
|
|
103
106
|
|| props.anonymous
|
|
104
107
|
|| uniqueNamesGenerator(nameGeneratorConfig))
|
|
105
108
|
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
</a>
|
|
16
16
|
<div class="align-items-center flex-grow-1 justify-content-between hidden absolute w-full md:w-auto surface-overlay
|
|
17
|
-
right-0 top-100 z-
|
|
17
|
+
right-0 top-100 z-5 shadow-2">
|
|
18
18
|
<loading-zone suspense>
|
|
19
19
|
<template v-slot:loading>
|
|
20
20
|
<div class="flex align-items-center justify-content-center top-0 left-0 notifications-loading">
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="flex flex-row align-items-center">
|
|
3
|
+
<AutoComplete v-model="selectedCountry" dropdown optionLabel="dial_code" placeholder="+XX" forceSelection
|
|
4
|
+
:suggestions="filteredCountries" @complete="searchCountry"
|
|
5
|
+
class="mr-2 w-14rem">
|
|
6
|
+
<template #option="slotProps">
|
|
7
|
+
<div class="flex align-items-center">
|
|
8
|
+
<img :alt="slotProps.option.name"
|
|
9
|
+
src="../../public/images/flag_placeholder.png"
|
|
10
|
+
:class="`flag flag-${slotProps.option.code.toLowerCase()} mr-2`"
|
|
11
|
+
style="width: 18px; height: 12.27px" />
|
|
12
|
+
<div>{{ slotProps.option.name }}</div>
|
|
13
|
+
</div>
|
|
14
|
+
</template>}}
|
|
15
|
+
</AutoComplete>
|
|
16
|
+
<InputText v-model="rest" :disabled="!selectedCountry" class="w-full"
|
|
17
|
+
pattern="[0-9 ]*" inputmode="numeric" ref="phoneInput"
|
|
18
|
+
@keyup="e => e.target.value = e.target.value.replace(/[^0-9 ]/g, '')"/>
|
|
19
|
+
</div>
|
|
20
|
+
</template>
|
|
21
|
+
|
|
22
|
+
<script setup>
|
|
23
|
+
|
|
24
|
+
import AutoComplete from 'primevue/autocomplete'
|
|
25
|
+
import InputText from 'primevue/inputtext'
|
|
26
|
+
|
|
27
|
+
import countries from '../utils/countries.js'
|
|
28
|
+
|
|
29
|
+
import { defineProps, defineModel, toRefs, ref, computed, watch } from 'vue'
|
|
30
|
+
|
|
31
|
+
const phoneInput = ref()
|
|
32
|
+
|
|
33
|
+
const value = defineModel({
|
|
34
|
+
type: String,
|
|
35
|
+
required: true
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
const props = defineProps({
|
|
39
|
+
id: {
|
|
40
|
+
type: String,
|
|
41
|
+
required: true
|
|
42
|
+
},
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
const selectedCountry = ref()
|
|
46
|
+
watch(value, (newValue) => {
|
|
47
|
+
if(!newValue) return
|
|
48
|
+
const found = countries.find((country) => newValue.startsWith(country.dial_code))
|
|
49
|
+
if(found) {
|
|
50
|
+
selectedCountry.value = found
|
|
51
|
+
if(phoneInput.value?.$el) {
|
|
52
|
+
const el = phoneInput.value.$el
|
|
53
|
+
//console.log("PHONE INPUT", el)
|
|
54
|
+
setTimeout(() => {
|
|
55
|
+
el.focus()
|
|
56
|
+
}, 100)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
watch(selectedCountry, (country) => {
|
|
61
|
+
if(!country) return
|
|
62
|
+
const currentCountry = value.value && countries.find((country) => value.value.startsWith(country.dial_code))
|
|
63
|
+
const code = typeof country === 'object' ? country.dial_code : country.replace(/[^\d]/g, '')
|
|
64
|
+
if(currentCountry) {
|
|
65
|
+
value.value = value.value.replace(currentCountry.dial_code, code)
|
|
66
|
+
} else {
|
|
67
|
+
value.value = code
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
const rest = computed({
|
|
72
|
+
get: () => value.value && (value.value
|
|
73
|
+
.replace(selectedCountry.value?.dial_code, '')
|
|
74
|
+
.replace(/[^\d ]/g, '')),
|
|
75
|
+
set: (rest) => value.value = selectedCountry.value?.dial_code + rest.replace(/[^\d ]/g, '')
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
const filteredCountries = ref(countries)
|
|
79
|
+
|
|
80
|
+
function searchCountry(event) {
|
|
81
|
+
const numbers = event.query.replace(/[^\d]/g, '')
|
|
82
|
+
console.log("Search country", event.query, numbers, selectedCountry.value)
|
|
83
|
+
if(selectedCountry.value !== null && typeof selectedCountry.value === 'object') selectedCountry.value = null
|
|
84
|
+
filteredCountries.value = countries.filter((country) =>
|
|
85
|
+
country.name.toLowerCase().startsWith(event.query.toLowerCase())
|
|
86
|
+
|| country.code.toLowerCase().startsWith(event.query.toLowerCase())
|
|
87
|
+
|| (numbers.length > 0 && country.dial_code.replace(/[^\d]/g, '').startsWith(numbers))
|
|
88
|
+
)
|
|
89
|
+
console.log("Found", filteredCountries.value)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
import { usePath, live } from '@live-change/vue3-ssr'
|
|
93
|
+
const path = usePath()
|
|
94
|
+
const geoIpPath = path.geoIp.myCountry({})
|
|
95
|
+
|
|
96
|
+
const myCountry = await live(geoIpPath)
|
|
97
|
+
|
|
98
|
+
if(selectedCountry.value == null) {
|
|
99
|
+
selectedCountry.value = countries.find(c => c.code.toLowerCase() === myCountry.value.toLowerCase())
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
</script>
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
<style scoped lang="scss">
|
|
106
|
+
@import "../utils/flags.scss";
|
|
107
|
+
</style>
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="w-full lg:w-6 md:w-9" v-shared-element:form="{ duration: '300ms', includeChildren: true }">
|
|
3
|
+
<div class="surface-card p-4 shadow-2 border-round">
|
|
4
|
+
|
|
5
|
+
<div class="text-center mb-5">
|
|
6
|
+
<div class="text-900 text-3xl font-medium mb-3">Linkedin authentication</div>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<div v-if="state === 'canceled'" class="text-center">
|
|
10
|
+
<div class="mb-1">Authentication canceled by user</div>
|
|
11
|
+
<div class="flex flex-row">
|
|
12
|
+
<Button @click="back" label="Go back" icon="pi pi-arrow-left" class="w-full p-button-secondary mb-1" />
|
|
13
|
+
<Button @click="linkedinAuth" label="Try again" icon="pi pi-linkedin" class="w-full p-button-secondary mb-1" />
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
<div v-else-if="state === 'waiting'" class="text-center">
|
|
17
|
+
Authentication will open in this window.
|
|
18
|
+
</div>
|
|
19
|
+
<div v-else-if="state === 'working'" class="text-center">
|
|
20
|
+
Waiting for server...
|
|
21
|
+
</div>
|
|
22
|
+
<div v-else-if="state === 'error'" class="text-center">
|
|
23
|
+
<div>Error during authentication:</div>
|
|
24
|
+
<div>{{ error }}</div>
|
|
25
|
+
</div>
|
|
26
|
+
<div v-else>
|
|
27
|
+
Unknown authentication state: {{ state }}
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
</template>
|
|
33
|
+
|
|
34
|
+
<script setup>
|
|
35
|
+
import { defineProps, toRefs, ref, onMounted, inject } from 'vue'
|
|
36
|
+
|
|
37
|
+
import { useRouter } from 'vue-router'
|
|
38
|
+
const router = useRouter()
|
|
39
|
+
|
|
40
|
+
const workingZone = inject('workingZone')
|
|
41
|
+
|
|
42
|
+
import { linkedinAuthRedirect } from '../utils/linkedinAuth.js'
|
|
43
|
+
|
|
44
|
+
const props = defineProps({
|
|
45
|
+
action: {
|
|
46
|
+
type: String,
|
|
47
|
+
default: 'signInOrSignUp'
|
|
48
|
+
},
|
|
49
|
+
accessType: {
|
|
50
|
+
type: String,
|
|
51
|
+
default: 'offline', //'online'
|
|
52
|
+
},
|
|
53
|
+
scopes: {
|
|
54
|
+
type: Array,
|
|
55
|
+
default: () => ['profile', 'email', 'openid']
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
const { action, accessType, scopes } = toRefs(props)
|
|
60
|
+
const state = ref('waiting')
|
|
61
|
+
const error = ref(null)
|
|
62
|
+
|
|
63
|
+
function linkedinAuth() {
|
|
64
|
+
state.value = 'waiting'
|
|
65
|
+
|
|
66
|
+
workingZone.addPromise('linkedin auth', new Promise((resolve, reject) => {
|
|
67
|
+
setTimeout(() => {
|
|
68
|
+
state.value = 'error'
|
|
69
|
+
error.value = 'redirect_timeout'
|
|
70
|
+
// return reject('redirect timeout?!')
|
|
71
|
+
return resolve()
|
|
72
|
+
}, 4000)
|
|
73
|
+
}))
|
|
74
|
+
|
|
75
|
+
linkedinAuthRedirect({
|
|
76
|
+
scope: (scopes.value ?? []).join(' '),
|
|
77
|
+
redirectUri: document.location.protocol + '//' + document.location.host
|
|
78
|
+
+ router.resolve({ name: 'user:linkedinAuthReturn', params: { action: action.value } }).href,
|
|
79
|
+
accessType: accessType.value
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function back() {
|
|
85
|
+
router.go(-1)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
onMounted(() => {
|
|
89
|
+
linkedinAuth()
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
</script>
|
|
93
|
+
|
|
94
|
+
<style scoped>
|
|
95
|
+
|
|
96
|
+
</style>
|