dauth-context-react 6.2.0 → 6.4.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/dist/index.d.mts +11 -3
- package/dist/index.d.ts +11 -3
- package/dist/index.js +235 -19
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +235 -19
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/DauthProfileModal.tsx +215 -26
- package/src/api/dauth.api.ts +17 -0
- package/src/api/interfaces/dauth.api.responses.ts +9 -0
- package/src/index.tsx +9 -0
- package/src/initialDauthState.ts +1 -0
- package/src/interfaces.ts +11 -2
- package/src/reducer/dauth.actions.ts +31 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dauth-context-react",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.4.0",
|
|
4
4
|
"description": "React provider and hook for passwordless authentication via the Dauth service (BFF pattern with httpOnly cookies)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "David T. Pizarro Frick",
|
|
@@ -299,6 +299,7 @@ export function DauthProfileModal({
|
|
|
299
299
|
getPasskeyCredentials,
|
|
300
300
|
registerPasskey,
|
|
301
301
|
deletePasskeyCredential,
|
|
302
|
+
uploadAvatar,
|
|
302
303
|
} = useDauth();
|
|
303
304
|
const isDesktop = useMediaQuery('(min-width: 641px)');
|
|
304
305
|
const phase = useModalAnimation(open);
|
|
@@ -314,6 +315,12 @@ export function DauthProfileModal({
|
|
|
314
315
|
const [lastname, setLastname] = useState('');
|
|
315
316
|
const [nickname, setNickname] = useState('');
|
|
316
317
|
const [country, setCountry] = useState('');
|
|
318
|
+
const [telPrefix, setTelPrefix] = useState('');
|
|
319
|
+
const [telSuffix, setTelSuffix] = useState('');
|
|
320
|
+
const [birthDate, setBirthDate] = useState('');
|
|
321
|
+
const [customFieldValues, setCustomFieldValues] = useState<
|
|
322
|
+
Record<string, string>
|
|
323
|
+
>({});
|
|
317
324
|
const [populated, setPopulated] = useState(false);
|
|
318
325
|
|
|
319
326
|
// Status
|
|
@@ -352,6 +359,20 @@ export function DauthProfileModal({
|
|
|
352
359
|
setLastname(user.lastname || '');
|
|
353
360
|
setNickname(user.nickname || '');
|
|
354
361
|
setCountry(user.country || '');
|
|
362
|
+
setTelPrefix(user.telPrefix || '');
|
|
363
|
+
setTelSuffix(user.telSuffix || '');
|
|
364
|
+
setBirthDate(
|
|
365
|
+
user.birthDate
|
|
366
|
+
? new Date(user.birthDate)
|
|
367
|
+
.toISOString()
|
|
368
|
+
.split('T')[0]
|
|
369
|
+
: ''
|
|
370
|
+
);
|
|
371
|
+
const cf: Record<string, string> = {};
|
|
372
|
+
for (const f of domain.customFields ?? []) {
|
|
373
|
+
cf[f.key] = user.customFields?.[f.key] ?? '';
|
|
374
|
+
}
|
|
375
|
+
setCustomFieldValues(cf);
|
|
355
376
|
setPopulated(true);
|
|
356
377
|
}
|
|
357
378
|
if (!open) {
|
|
@@ -414,13 +435,36 @@ export function DauthProfileModal({
|
|
|
414
435
|
|
|
415
436
|
const hasChanges = useMemo(() => {
|
|
416
437
|
if (!user?._id) return false;
|
|
438
|
+
const origBirthDate = user.birthDate
|
|
439
|
+
? new Date(user.birthDate).toISOString().split('T')[0]
|
|
440
|
+
: '';
|
|
441
|
+
const cfChanged = (domain.customFields ?? []).some(
|
|
442
|
+
(f) =>
|
|
443
|
+
(customFieldValues[f.key] ?? '') !==
|
|
444
|
+
(user.customFields?.[f.key] ?? '')
|
|
445
|
+
);
|
|
417
446
|
return (
|
|
418
447
|
name !== (user.name || '') ||
|
|
419
448
|
lastname !== (user.lastname || '') ||
|
|
420
449
|
nickname !== (user.nickname || '') ||
|
|
421
|
-
country !== (user.country || '')
|
|
450
|
+
country !== (user.country || '') ||
|
|
451
|
+
telPrefix !== (user.telPrefix || '') ||
|
|
452
|
+
telSuffix !== (user.telSuffix || '') ||
|
|
453
|
+
birthDate !== origBirthDate ||
|
|
454
|
+
cfChanged
|
|
422
455
|
);
|
|
423
|
-
}, [
|
|
456
|
+
}, [
|
|
457
|
+
name,
|
|
458
|
+
lastname,
|
|
459
|
+
nickname,
|
|
460
|
+
country,
|
|
461
|
+
telPrefix,
|
|
462
|
+
telSuffix,
|
|
463
|
+
birthDate,
|
|
464
|
+
customFieldValues,
|
|
465
|
+
user,
|
|
466
|
+
domain.customFields,
|
|
467
|
+
]);
|
|
424
468
|
|
|
425
469
|
const canSave =
|
|
426
470
|
name.trim().length > 0 && hasChanges && !saving;
|
|
@@ -428,10 +472,18 @@ export function DauthProfileModal({
|
|
|
428
472
|
const handleSave = useCallback(async () => {
|
|
429
473
|
setSaving(true);
|
|
430
474
|
setStatus(null);
|
|
431
|
-
const fields: Record<string,
|
|
475
|
+
const fields: Record<string, any> = { name };
|
|
432
476
|
if (hasField('lastname')) fields.lastname = lastname;
|
|
433
477
|
if (hasField('nickname')) fields.nickname = nickname;
|
|
434
478
|
if (hasField('country')) fields.country = country;
|
|
479
|
+
if (hasField('tel_prefix'))
|
|
480
|
+
fields.telPrefix = telPrefix;
|
|
481
|
+
if (hasField('tel_suffix'))
|
|
482
|
+
fields.telSuffix = telSuffix;
|
|
483
|
+
if (hasField('birth_date') && birthDate)
|
|
484
|
+
fields.birthDate = birthDate;
|
|
485
|
+
if ((domain.customFields ?? []).length > 0)
|
|
486
|
+
fields.customFields = customFieldValues;
|
|
435
487
|
const ok = await updateUser(fields);
|
|
436
488
|
setSaving(false);
|
|
437
489
|
if (ok) {
|
|
@@ -445,7 +497,19 @@ export function DauthProfileModal({
|
|
|
445
497
|
message: 'Something went wrong. Please try again.',
|
|
446
498
|
});
|
|
447
499
|
}
|
|
448
|
-
}, [
|
|
500
|
+
}, [
|
|
501
|
+
name,
|
|
502
|
+
lastname,
|
|
503
|
+
nickname,
|
|
504
|
+
country,
|
|
505
|
+
telPrefix,
|
|
506
|
+
telSuffix,
|
|
507
|
+
birthDate,
|
|
508
|
+
customFieldValues,
|
|
509
|
+
hasField,
|
|
510
|
+
updateUser,
|
|
511
|
+
domain.customFields,
|
|
512
|
+
]);
|
|
449
513
|
|
|
450
514
|
const handleDelete = useCallback(async () => {
|
|
451
515
|
setDeleting(true);
|
|
@@ -507,20 +571,22 @@ export function DauthProfileModal({
|
|
|
507
571
|
);
|
|
508
572
|
|
|
509
573
|
const handleAvatarClick = useCallback(() => {
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
}
|
|
513
|
-
}, [onAvatarUpload]);
|
|
574
|
+
avatarInputRef.current?.click();
|
|
575
|
+
}, []);
|
|
514
576
|
|
|
515
577
|
const handleAvatarChange = useCallback(
|
|
516
578
|
async (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
517
579
|
const file = e.target.files?.[0];
|
|
518
|
-
if (!file
|
|
580
|
+
if (!file) return;
|
|
519
581
|
setUploadingAvatar(true);
|
|
520
582
|
try {
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
583
|
+
if (onAvatarUpload) {
|
|
584
|
+
const url = await onAvatarUpload(file);
|
|
585
|
+
if (url) {
|
|
586
|
+
await updateUser({ avatar: url } as any);
|
|
587
|
+
}
|
|
588
|
+
} else {
|
|
589
|
+
await uploadAvatar(file);
|
|
524
590
|
}
|
|
525
591
|
} catch {
|
|
526
592
|
// Error handled by onError callback
|
|
@@ -530,7 +596,7 @@ export function DauthProfileModal({
|
|
|
530
596
|
avatarInputRef.current.value = '';
|
|
531
597
|
}
|
|
532
598
|
},
|
|
533
|
-
[onAvatarUpload, updateUser]
|
|
599
|
+
[onAvatarUpload, updateUser, uploadAvatar]
|
|
534
600
|
);
|
|
535
601
|
|
|
536
602
|
const handleSignOut = useCallback(() => {
|
|
@@ -713,9 +779,7 @@ export function DauthProfileModal({
|
|
|
713
779
|
<div
|
|
714
780
|
style={{
|
|
715
781
|
...avatarCircle,
|
|
716
|
-
cursor:
|
|
717
|
-
? 'pointer'
|
|
718
|
-
: 'default',
|
|
782
|
+
cursor: 'pointer',
|
|
719
783
|
position: 'relative' as const,
|
|
720
784
|
}}
|
|
721
785
|
onClick={handleAvatarClick}
|
|
@@ -735,22 +799,20 @@ export function DauthProfileModal({
|
|
|
735
799
|
) : (
|
|
736
800
|
avatarInitial
|
|
737
801
|
)}
|
|
738
|
-
{
|
|
802
|
+
{!uploadingAvatar && (
|
|
739
803
|
<div style={avatarOverlay}>
|
|
740
804
|
<IconCamera />
|
|
741
805
|
</div>
|
|
742
806
|
)}
|
|
743
807
|
</div>
|
|
744
808
|
<div style={emailText}>{user.email}</div>
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
/>
|
|
753
|
-
)}
|
|
809
|
+
<input
|
|
810
|
+
ref={avatarInputRef}
|
|
811
|
+
type="file"
|
|
812
|
+
accept="image/*"
|
|
813
|
+
style={{ display: 'none' }}
|
|
814
|
+
onChange={handleAvatarChange}
|
|
815
|
+
/>
|
|
754
816
|
</div>
|
|
755
817
|
|
|
756
818
|
{/* Status */}
|
|
@@ -862,6 +924,133 @@ export function DauthProfileModal({
|
|
|
862
924
|
/>
|
|
863
925
|
</div>
|
|
864
926
|
)}
|
|
927
|
+
|
|
928
|
+
{(hasField('tel_prefix') ||
|
|
929
|
+
hasField('tel_suffix')) && (
|
|
930
|
+
<div style={fieldGroup}>
|
|
931
|
+
<div style={label}>
|
|
932
|
+
Phone
|
|
933
|
+
{isRequired('tel_prefix') ||
|
|
934
|
+
isRequired('tel_suffix')
|
|
935
|
+
? ' *'
|
|
936
|
+
: ''}
|
|
937
|
+
</div>
|
|
938
|
+
<div
|
|
939
|
+
style={{
|
|
940
|
+
display: 'flex',
|
|
941
|
+
gap: 8,
|
|
942
|
+
}}
|
|
943
|
+
>
|
|
944
|
+
{hasField('tel_prefix') && (
|
|
945
|
+
<input
|
|
946
|
+
id="dauth-tel-prefix"
|
|
947
|
+
type="text"
|
|
948
|
+
value={telPrefix}
|
|
949
|
+
onChange={(e) =>
|
|
950
|
+
setTelPrefix(e.target.value)
|
|
951
|
+
}
|
|
952
|
+
placeholder="+34"
|
|
953
|
+
disabled={saving}
|
|
954
|
+
style={{
|
|
955
|
+
...input,
|
|
956
|
+
width: 80,
|
|
957
|
+
flexShrink: 0,
|
|
958
|
+
}}
|
|
959
|
+
onFocus={inputFocusHandler}
|
|
960
|
+
onBlur={inputBlurHandler}
|
|
961
|
+
aria-label="Phone prefix"
|
|
962
|
+
/>
|
|
963
|
+
)}
|
|
964
|
+
{hasField('tel_suffix') && (
|
|
965
|
+
<input
|
|
966
|
+
id="dauth-tel-suffix"
|
|
967
|
+
type="tel"
|
|
968
|
+
value={telSuffix}
|
|
969
|
+
onChange={(e) =>
|
|
970
|
+
setTelSuffix(e.target.value)
|
|
971
|
+
}
|
|
972
|
+
placeholder="612 345 678"
|
|
973
|
+
disabled={saving}
|
|
974
|
+
style={{
|
|
975
|
+
...input,
|
|
976
|
+
flex: 1,
|
|
977
|
+
}}
|
|
978
|
+
onFocus={inputFocusHandler}
|
|
979
|
+
onBlur={inputBlurHandler}
|
|
980
|
+
aria-label="Phone number"
|
|
981
|
+
/>
|
|
982
|
+
)}
|
|
983
|
+
</div>
|
|
984
|
+
</div>
|
|
985
|
+
)}
|
|
986
|
+
|
|
987
|
+
{hasField('birth_date') && (
|
|
988
|
+
<div style={fieldGroup}>
|
|
989
|
+
<label
|
|
990
|
+
htmlFor="dauth-birthdate"
|
|
991
|
+
style={label}
|
|
992
|
+
>
|
|
993
|
+
Birth date
|
|
994
|
+
{isRequired('birth_date')
|
|
995
|
+
? ' *'
|
|
996
|
+
: ''}
|
|
997
|
+
</label>
|
|
998
|
+
<input
|
|
999
|
+
id="dauth-birthdate"
|
|
1000
|
+
type="date"
|
|
1001
|
+
value={birthDate}
|
|
1002
|
+
onChange={(e) =>
|
|
1003
|
+
setBirthDate(e.target.value)
|
|
1004
|
+
}
|
|
1005
|
+
disabled={saving}
|
|
1006
|
+
style={input}
|
|
1007
|
+
onFocus={inputFocusHandler}
|
|
1008
|
+
onBlur={inputBlurHandler}
|
|
1009
|
+
/>
|
|
1010
|
+
</div>
|
|
1011
|
+
)}
|
|
1012
|
+
|
|
1013
|
+
{(domain.customFields ?? []).length >
|
|
1014
|
+
0 && (
|
|
1015
|
+
<>
|
|
1016
|
+
<hr style={separator} />
|
|
1017
|
+
{domain.customFields!.map((cf) => (
|
|
1018
|
+
<div
|
|
1019
|
+
key={cf.key}
|
|
1020
|
+
style={fieldGroup}
|
|
1021
|
+
>
|
|
1022
|
+
<label
|
|
1023
|
+
htmlFor={`dauth-cf-${cf.key}`}
|
|
1024
|
+
style={label}
|
|
1025
|
+
>
|
|
1026
|
+
{cf.label}
|
|
1027
|
+
{cf.required ? ' *' : ''}
|
|
1028
|
+
</label>
|
|
1029
|
+
<input
|
|
1030
|
+
id={`dauth-cf-${cf.key}`}
|
|
1031
|
+
type="text"
|
|
1032
|
+
value={
|
|
1033
|
+
customFieldValues[cf.key] ??
|
|
1034
|
+
''
|
|
1035
|
+
}
|
|
1036
|
+
onChange={(e) =>
|
|
1037
|
+
setCustomFieldValues(
|
|
1038
|
+
(prev) => ({
|
|
1039
|
+
...prev,
|
|
1040
|
+
[cf.key]:
|
|
1041
|
+
e.target.value,
|
|
1042
|
+
})
|
|
1043
|
+
)
|
|
1044
|
+
}
|
|
1045
|
+
disabled={saving}
|
|
1046
|
+
style={input}
|
|
1047
|
+
onFocus={inputFocusHandler}
|
|
1048
|
+
onBlur={inputBlurHandler}
|
|
1049
|
+
/>
|
|
1050
|
+
</div>
|
|
1051
|
+
))}
|
|
1052
|
+
</>
|
|
1053
|
+
)}
|
|
865
1054
|
</div>
|
|
866
1055
|
|
|
867
1056
|
{/* Language selector */}
|
package/src/api/dauth.api.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
IPasskeyRegistrationStartResponse,
|
|
9
9
|
IPasskeyRegistrationFinishResponse,
|
|
10
10
|
IDeletePasskeyResponse,
|
|
11
|
+
IUploadAvatarResponse,
|
|
11
12
|
} from './interfaces/dauth.api.responses';
|
|
12
13
|
|
|
13
14
|
function getCsrfToken(): string {
|
|
@@ -158,3 +159,19 @@ export async function deletePasskeyCredentialAPI(
|
|
|
158
159
|
const data = await response.json();
|
|
159
160
|
return { response, data };
|
|
160
161
|
}
|
|
162
|
+
|
|
163
|
+
export async function uploadAvatarAPI(
|
|
164
|
+
basePath: string,
|
|
165
|
+
file: File
|
|
166
|
+
): Promise<IUploadAvatarResponse> {
|
|
167
|
+
const formData = new FormData();
|
|
168
|
+
formData.append('avatar', file);
|
|
169
|
+
const response = await fetch(`${basePath}/avatar`, {
|
|
170
|
+
method: 'POST',
|
|
171
|
+
headers: { 'X-CSRF-Token': getCsrfToken() },
|
|
172
|
+
credentials: 'include',
|
|
173
|
+
body: formData,
|
|
174
|
+
});
|
|
175
|
+
const data = await response.json();
|
|
176
|
+
return { response, data };
|
|
177
|
+
}
|
package/src/index.tsx
CHANGED
|
@@ -17,6 +17,7 @@ import type {
|
|
|
17
17
|
IDauthAuthMethods,
|
|
18
18
|
IDauthUser,
|
|
19
19
|
IFormField,
|
|
20
|
+
ICustomField,
|
|
20
21
|
IModalTheme,
|
|
21
22
|
IPasskeyCredential,
|
|
22
23
|
DauthProfileModalProps,
|
|
@@ -27,6 +28,7 @@ export type {
|
|
|
27
28
|
IDauthProviderProps,
|
|
28
29
|
IDauthAuthMethods,
|
|
29
30
|
IFormField,
|
|
31
|
+
ICustomField,
|
|
30
32
|
IModalTheme,
|
|
31
33
|
IPasskeyCredential,
|
|
32
34
|
DauthProfileModalProps,
|
|
@@ -133,6 +135,11 @@ export const DauthProvider: React.FC<IDauthProviderProps> = (
|
|
|
133
135
|
[ctx]
|
|
134
136
|
);
|
|
135
137
|
|
|
138
|
+
const uploadAvatar = useCallback(
|
|
139
|
+
(file: File) => action.uploadAvatarAction(ctx, file),
|
|
140
|
+
[ctx]
|
|
141
|
+
);
|
|
142
|
+
|
|
136
143
|
const memoProvider = useMemo(
|
|
137
144
|
() => ({
|
|
138
145
|
...dauthState,
|
|
@@ -143,6 +150,7 @@ export const DauthProvider: React.FC<IDauthProviderProps> = (
|
|
|
143
150
|
getPasskeyCredentials,
|
|
144
151
|
registerPasskey,
|
|
145
152
|
deletePasskeyCredential,
|
|
153
|
+
uploadAvatar,
|
|
146
154
|
}),
|
|
147
155
|
[
|
|
148
156
|
dauthState,
|
|
@@ -153,6 +161,7 @@ export const DauthProvider: React.FC<IDauthProviderProps> = (
|
|
|
153
161
|
getPasskeyCredentials,
|
|
154
162
|
registerPasskey,
|
|
155
163
|
deletePasskeyCredential,
|
|
164
|
+
uploadAvatar,
|
|
156
165
|
]
|
|
157
166
|
);
|
|
158
167
|
|
package/src/initialDauthState.ts
CHANGED
|
@@ -17,6 +17,7 @@ const initialDauthState: IDauthState = {
|
|
|
17
17
|
getPasskeyCredentials: () => Promise.resolve([]),
|
|
18
18
|
registerPasskey: () => Promise.resolve(null),
|
|
19
19
|
deletePasskeyCredential: () => Promise.resolve(false),
|
|
20
|
+
uploadAvatar: () => Promise.resolve(false),
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
export default initialDauthState;
|
package/src/interfaces.ts
CHANGED
|
@@ -16,6 +16,7 @@ export interface IDauthUser {
|
|
|
16
16
|
birthDate?: Date;
|
|
17
17
|
country?: string;
|
|
18
18
|
metadata?: Record<string, unknown>;
|
|
19
|
+
customFields?: Record<string, string>;
|
|
19
20
|
createdAt: Date;
|
|
20
21
|
updatedAt: Date;
|
|
21
22
|
lastLogin: Date;
|
|
@@ -36,6 +37,12 @@ export interface IFormField {
|
|
|
36
37
|
required: boolean;
|
|
37
38
|
}
|
|
38
39
|
|
|
40
|
+
export interface ICustomField {
|
|
41
|
+
key: string;
|
|
42
|
+
label: string;
|
|
43
|
+
required: boolean;
|
|
44
|
+
}
|
|
45
|
+
|
|
39
46
|
export interface IModalTheme {
|
|
40
47
|
accent?: string;
|
|
41
48
|
accentHover?: string;
|
|
@@ -53,6 +60,7 @@ export interface IDauthDomainState {
|
|
|
53
60
|
allowedOrigins: string[];
|
|
54
61
|
authMethods?: IDauthAuthMethods;
|
|
55
62
|
formFields?: IFormField[];
|
|
63
|
+
customFields?: ICustomField[];
|
|
56
64
|
modalTheme?: IModalTheme;
|
|
57
65
|
}
|
|
58
66
|
|
|
@@ -81,14 +89,15 @@ export interface IDauthState {
|
|
|
81
89
|
deletePasskeyCredential: (
|
|
82
90
|
credentialId: string
|
|
83
91
|
) => Promise<boolean>;
|
|
92
|
+
uploadAvatar: (file: File) => Promise<boolean>;
|
|
84
93
|
}
|
|
85
94
|
|
|
86
95
|
export interface DauthProfileModalProps {
|
|
87
96
|
open: boolean;
|
|
88
97
|
onClose: () => void;
|
|
89
|
-
/** Optional
|
|
98
|
+
/** Optional override for avatar upload.
|
|
90
99
|
* Receives a File, should return the URL string.
|
|
91
|
-
* If not provided, the
|
|
100
|
+
* If not provided, uses the built-in upload via the auth proxy. */
|
|
92
101
|
onAvatarUpload?: (file: File) => Promise<string>;
|
|
93
102
|
}
|
|
94
103
|
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
startPasskeyRegistrationAPI,
|
|
9
9
|
finishPasskeyRegistrationAPI,
|
|
10
10
|
deletePasskeyCredentialAPI,
|
|
11
|
+
uploadAvatarAPI,
|
|
11
12
|
} from '../api/dauth.api';
|
|
12
13
|
import type { IPasskeyCredential } from '../api/interfaces/dauth.api.responses';
|
|
13
14
|
import { createPasskeyCredential } from '../webauthn';
|
|
@@ -239,6 +240,36 @@ export async function deletePasskeyCredentialAction(
|
|
|
239
240
|
}
|
|
240
241
|
}
|
|
241
242
|
|
|
243
|
+
export async function uploadAvatarAction(
|
|
244
|
+
ctx: ActionContext,
|
|
245
|
+
file: File
|
|
246
|
+
): Promise<boolean> {
|
|
247
|
+
const { dispatch, authProxyPath, onError } = ctx;
|
|
248
|
+
try {
|
|
249
|
+
const result = await uploadAvatarAPI(authProxyPath, file);
|
|
250
|
+
if (result.response.status === 200) {
|
|
251
|
+
dispatch({
|
|
252
|
+
type: DauthTypes.UPDATE_USER,
|
|
253
|
+
payload: result.data.user,
|
|
254
|
+
});
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
onError(
|
|
258
|
+
new Error(
|
|
259
|
+
'Avatar upload error: ' + result.data.message
|
|
260
|
+
)
|
|
261
|
+
);
|
|
262
|
+
return false;
|
|
263
|
+
} catch (error) {
|
|
264
|
+
onError(
|
|
265
|
+
error instanceof Error
|
|
266
|
+
? error
|
|
267
|
+
: new Error('Avatar upload error')
|
|
268
|
+
);
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
242
273
|
export const resetUser = (dispatch: React.Dispatch<any>) => {
|
|
243
274
|
return dispatch({
|
|
244
275
|
type: DauthTypes.LOGIN,
|