@memori.ai/memori-react 8.7.3 → 8.7.5
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/CHANGELOG.md +29 -0
- package/dist/components/Chat/Chat.js +1 -1
- package/dist/components/Chat/Chat.js.map +1 -1
- package/dist/components/LoginDrawer/LoginDrawer.d.ts +2 -2
- package/dist/components/LoginDrawer/LoginDrawer.js +181 -139
- package/dist/components/LoginDrawer/LoginDrawer.js.map +1 -1
- package/dist/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.d.ts +2 -2
- package/dist/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js +61 -32
- package/dist/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js.map +1 -1
- package/dist/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.css +1 -1
- package/dist/components/MemoriWidget/MemoriWidget.js +4 -94
- package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/dist/components/layouts/HiddenChat.js +3 -9
- package/dist/components/layouts/HiddenChat.js.map +1 -1
- package/dist/components/layouts/hidden-chat.css +14 -3
- package/dist/helpers/utils.js +1 -1
- package/dist/helpers/utils.js.map +1 -1
- package/esm/components/Chat/Chat.js +1 -1
- package/esm/components/Chat/Chat.js.map +1 -1
- package/esm/components/LoginDrawer/LoginDrawer.d.ts +2 -2
- package/esm/components/LoginDrawer/LoginDrawer.js +183 -141
- package/esm/components/LoginDrawer/LoginDrawer.js.map +1 -1
- package/esm/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.d.ts +2 -2
- package/esm/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js +62 -33
- package/esm/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js.map +1 -1
- package/esm/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.css +1 -1
- package/esm/components/MemoriWidget/MemoriWidget.js +4 -94
- package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/esm/components/layouts/HiddenChat.js +3 -9
- package/esm/components/layouts/HiddenChat.js.map +1 -1
- package/esm/components/layouts/hidden-chat.css +14 -3
- package/esm/helpers/utils.js +1 -1
- package/esm/helpers/utils.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Chat/Chat.tsx +1 -1
- package/src/components/LoginDrawer/LoginDrawer.test.tsx +12 -12
- package/src/components/LoginDrawer/LoginDrawer.tsx +391 -321
- package/src/components/MemoriArtifactSystem/ArtifactDrawer.stories.tsx +96 -179
- package/src/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.tsx +88 -39
- package/src/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.css +1 -1
- package/src/components/MemoriWidget/MemoriWidget.tsx +5 -135
- package/src/components/layouts/HiddenChat.tsx +4 -9
- package/src/components/layouts/hidden-chat.css +14 -3
- package/src/helpers/utils.ts +1 -1
- package/src/components/AccountForm/AccountForm.tsx +0 -325
|
@@ -1253,7 +1253,7 @@ const MemoriWidget = ({
|
|
|
1253
1253
|
// (i: Invitation) => i.type === 'GIVER' && i.state === 'ACCEPTED'
|
|
1254
1254
|
// );
|
|
1255
1255
|
|
|
1256
|
-
// if (giverInvitation) {
|
|
1256
|
+
// if (giverInvitation) {x
|
|
1257
1257
|
// memori.giverTag = giverInvitation.tag;
|
|
1258
1258
|
// memori.giverPIN = giverInvitation.pin;
|
|
1259
1259
|
// }
|
|
@@ -1548,136 +1548,6 @@ const MemoriWidget = ({
|
|
|
1548
1548
|
return null;
|
|
1549
1549
|
};
|
|
1550
1550
|
|
|
1551
|
-
const [chatLogs, setChatLogs] = useState<any[]>([]);
|
|
1552
|
-
const resumeSession = async (
|
|
1553
|
-
chatLog: ChatLog,
|
|
1554
|
-
questionsAndAnswers: { question: string; answer: string }[],
|
|
1555
|
-
initialContextVars?: { [key: string]: string },
|
|
1556
|
-
initialQuestion?: string,
|
|
1557
|
-
birthDate?: string
|
|
1558
|
-
) => {
|
|
1559
|
-
// Set loading state while reopening session
|
|
1560
|
-
setLoading(true);
|
|
1561
|
-
|
|
1562
|
-
// Get birth date from local storage if not provided
|
|
1563
|
-
let storageBirthDate = getLocalConfig<string | undefined>(
|
|
1564
|
-
'birthDate',
|
|
1565
|
-
undefined
|
|
1566
|
-
);
|
|
1567
|
-
let userBirthDate = birthDate ?? storageBirthDate;
|
|
1568
|
-
// // console.log('[REOPEN_SESSION] Using birth date:', userBirthDate);
|
|
1569
|
-
|
|
1570
|
-
try {
|
|
1571
|
-
// Show age verification if required and birth date not provided
|
|
1572
|
-
if (!userBirthDate && !!minAge) {
|
|
1573
|
-
// // console.log('[REOPEN_SESSION] Age verification required, showing modal');
|
|
1574
|
-
setShowAgeVerification(true);
|
|
1575
|
-
return;
|
|
1576
|
-
}
|
|
1577
|
-
|
|
1578
|
-
// Check if authentication is needed based on privacy type and credentials
|
|
1579
|
-
if (
|
|
1580
|
-
memori.privacyType !== 'PUBLIC' &&
|
|
1581
|
-
!memoriPassword &&
|
|
1582
|
-
!memori.secretToken &&
|
|
1583
|
-
!memoriPwd &&
|
|
1584
|
-
!memoriTokens
|
|
1585
|
-
) {
|
|
1586
|
-
// // console.log('[REOPEN_SESSION] Authentication required, showing modal');
|
|
1587
|
-
setAuthModalState('password');
|
|
1588
|
-
return;
|
|
1589
|
-
}
|
|
1590
|
-
|
|
1591
|
-
// Get current URL as referral
|
|
1592
|
-
let referral;
|
|
1593
|
-
try {
|
|
1594
|
-
referral = (() => {
|
|
1595
|
-
return window.location.href;
|
|
1596
|
-
})();
|
|
1597
|
-
// console.log('[REOPEN_SESSION] Got referral:', referral);
|
|
1598
|
-
} catch (err) {
|
|
1599
|
-
console.debug('[REOPEN_SESSION] Error getting referral:', err);
|
|
1600
|
-
}
|
|
1601
|
-
|
|
1602
|
-
// Initialize session with provided parameters
|
|
1603
|
-
// // console.log('[REOPEN_SESSION] Initializing session...');
|
|
1604
|
-
const { sessionID, currentState, ...response } = await initSession({
|
|
1605
|
-
memoriID: memori.engineMemoriID ?? '',
|
|
1606
|
-
password: memoriPassword || memoriPwd || memori.secretToken,
|
|
1607
|
-
recoveryTokens: memoriTokens,
|
|
1608
|
-
tag: personification?.tag,
|
|
1609
|
-
pin: personification?.pin,
|
|
1610
|
-
continueFromChatLogID: chatLog.chatLogID,
|
|
1611
|
-
initialContextVars: {
|
|
1612
|
-
PATHNAME: window.location.pathname,
|
|
1613
|
-
ROUTE: window.location.pathname?.split('/')?.pop() || '',
|
|
1614
|
-
...(initialContextVars || {}),
|
|
1615
|
-
},
|
|
1616
|
-
initialQuestion,
|
|
1617
|
-
birthDate: userBirthDate,
|
|
1618
|
-
additionalInfo: {
|
|
1619
|
-
...(additionalInfo || {}),
|
|
1620
|
-
loginToken:
|
|
1621
|
-
userToken ?? loginToken ?? additionalInfo?.loginToken ?? authToken,
|
|
1622
|
-
language: getCultureCodeByLanguage(userLang),
|
|
1623
|
-
referral: referral,
|
|
1624
|
-
timeZoneOffset: new Date().getTimezoneOffset().toString(),
|
|
1625
|
-
},
|
|
1626
|
-
});
|
|
1627
|
-
|
|
1628
|
-
// Handle successful session initialization
|
|
1629
|
-
if (sessionID) {
|
|
1630
|
-
// // console.log('[REOPEN_SESSION] Session initialized successfully:', sessionID);
|
|
1631
|
-
setSessionId(sessionID);
|
|
1632
|
-
|
|
1633
|
-
// // console.log('[REOPEN_SESSION] Processing emission:', currentState.emission);
|
|
1634
|
-
// Set initial message or append to existing history
|
|
1635
|
-
setHistory(
|
|
1636
|
-
chatLog.lines.map(log => ({
|
|
1637
|
-
text: log.text,
|
|
1638
|
-
emitter: log.emitter,
|
|
1639
|
-
media: log.media?.map(m => ({
|
|
1640
|
-
...m,
|
|
1641
|
-
mediumID:
|
|
1642
|
-
'mediumID' in m ? String(m.mediumID) : crypto.randomUUID(),
|
|
1643
|
-
})),
|
|
1644
|
-
fromUser: log.inbound,
|
|
1645
|
-
initial: false,
|
|
1646
|
-
contextVars: log.contextVars,
|
|
1647
|
-
date: log.timestamp,
|
|
1648
|
-
}))
|
|
1649
|
-
);
|
|
1650
|
-
|
|
1651
|
-
setChatLogs(questionsAndAnswers);
|
|
1652
|
-
}
|
|
1653
|
-
|
|
1654
|
-
// Handle age restriction error
|
|
1655
|
-
else if (
|
|
1656
|
-
response?.resultMessage.startsWith('This Memori is aged restricted')
|
|
1657
|
-
) {
|
|
1658
|
-
console.error('[REOPEN_SESSION] Age restriction error:', response);
|
|
1659
|
-
toast.error(t('underageTwinSession', { age: minAge }));
|
|
1660
|
-
setGotErrorInOpening(true);
|
|
1661
|
-
}
|
|
1662
|
-
// Handle authentication error
|
|
1663
|
-
else if (response?.resultCode === 403) {
|
|
1664
|
-
console.error('[REOPEN_SESSION] Authentication error');
|
|
1665
|
-
setMemoriPwd(undefined);
|
|
1666
|
-
setAuthModalState('password');
|
|
1667
|
-
}
|
|
1668
|
-
// Handle other errors
|
|
1669
|
-
else {
|
|
1670
|
-
console.error('[REOPEN_SESSION] Other error:', response);
|
|
1671
|
-
toast.error(t(getErrori18nKey(response.resultCode)));
|
|
1672
|
-
setGotErrorInOpening(true);
|
|
1673
|
-
}
|
|
1674
|
-
} catch (err) {
|
|
1675
|
-
console.error('[RESUME_SESSION] Caught error:', err);
|
|
1676
|
-
}
|
|
1677
|
-
|
|
1678
|
-
setLoading(false);
|
|
1679
|
-
};
|
|
1680
|
-
|
|
1681
1551
|
const changeTag = async (
|
|
1682
1552
|
memoriId: string,
|
|
1683
1553
|
sessionId: string,
|
|
@@ -2513,10 +2383,11 @@ const MemoriWidget = ({
|
|
|
2513
2383
|
const { currentState, ...response } = await getSession(sessionID!);
|
|
2514
2384
|
|
|
2515
2385
|
if (response.resultCode !== 0 || !currentState) {
|
|
2386
|
+
const { chatLogs } = await getSessionChatLogs(sessionID!, sessionID!);
|
|
2516
2387
|
setGotErrorInOpening(true);
|
|
2517
2388
|
setSessionId(undefined);
|
|
2518
2389
|
setClickedStart(false);
|
|
2519
|
-
await onClickStart(undefined, true);
|
|
2390
|
+
await onClickStart(undefined, true, chatLogs?.[0]);
|
|
2520
2391
|
return;
|
|
2521
2392
|
}
|
|
2522
2393
|
|
|
@@ -2855,8 +2726,7 @@ const MemoriWidget = ({
|
|
|
2855
2726
|
const showFullHistory =
|
|
2856
2727
|
showOnlyLastMessages === undefined
|
|
2857
2728
|
? selectedLayout !== 'TOTEM' &&
|
|
2858
|
-
selectedLayout !== 'WEBSITE_ASSISTANT'
|
|
2859
|
-
selectedLayout !== 'HIDDEN_CHAT'
|
|
2729
|
+
selectedLayout !== 'WEBSITE_ASSISTANT'
|
|
2860
2730
|
: !showOnlyLastMessages;
|
|
2861
2731
|
|
|
2862
2732
|
const headerProps: HeaderProps = {
|
|
@@ -3331,7 +3201,7 @@ const MemoriWidget = ({
|
|
|
3331
3201
|
setShowLoginDrawer(false);
|
|
3332
3202
|
setLocalConfig('loginToken', token);
|
|
3333
3203
|
}}
|
|
3334
|
-
|
|
3204
|
+
setUser={setUser}
|
|
3335
3205
|
onLogout={() => {
|
|
3336
3206
|
if (!loginToken) return;
|
|
3337
3207
|
|
|
@@ -2,9 +2,9 @@ import React, { useState, useEffect, useRef } from 'react';
|
|
|
2
2
|
import Spin from '../ui/Spin';
|
|
3
3
|
import { LayoutProps } from '../MemoriWidget/MemoriWidget';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
|
+
import { useArtifact } from '../MemoriArtifactSystem/context/ArtifactContext';
|
|
5
6
|
import QuestionHelp from '../icons/QuestionHelp';
|
|
6
7
|
import Close from '../icons/Close';
|
|
7
|
-
import { useArtifact } from '../MemoriArtifactSystem/context/ArtifactContext';
|
|
8
8
|
|
|
9
9
|
const HiddenChatLayout: React.FC<LayoutProps> = ({
|
|
10
10
|
Header,
|
|
@@ -24,7 +24,7 @@ const HiddenChatLayout: React.FC<LayoutProps> = ({
|
|
|
24
24
|
const [fullScreen, setFullScreen] = useState(false);
|
|
25
25
|
const [hasTriggeredAutostart, setHasTriggeredAutostart] = useState(false);
|
|
26
26
|
|
|
27
|
-
const { state } = useArtifact();
|
|
27
|
+
const { state, closeArtifact } = useArtifact();
|
|
28
28
|
const { onClickStart, hasInitialSession } = startPanelProps || {};
|
|
29
29
|
|
|
30
30
|
// Use refs to store original sidebar properties to restore them later
|
|
@@ -72,17 +72,11 @@ const HiddenChatLayout: React.FC<LayoutProps> = ({
|
|
|
72
72
|
mainDiv.style.width = '100%';
|
|
73
73
|
mainDiv.style.marginRight = '0';
|
|
74
74
|
mainDiv.style.marginLeft = '0';
|
|
75
|
+
closeArtifact();
|
|
75
76
|
}
|
|
76
77
|
}, [isOpen, fullScreen]);
|
|
77
78
|
|
|
78
79
|
const handleSidebarToggle = () => {
|
|
79
|
-
console.log('[HiddenChatLayout] Sidebar toggle clicked:', {
|
|
80
|
-
currentState: isOpen,
|
|
81
|
-
autoStart,
|
|
82
|
-
sessionId,
|
|
83
|
-
hasInitialSession,
|
|
84
|
-
hasTriggeredAutostart
|
|
85
|
-
});
|
|
86
80
|
|
|
87
81
|
// Only trigger autostart when opening the sidebar for the first time
|
|
88
82
|
// and when we haven't already triggered it
|
|
@@ -202,6 +196,7 @@ const HiddenChatLayout: React.FC<LayoutProps> = ({
|
|
|
202
196
|
>
|
|
203
197
|
<QuestionHelp className="memori-icon" aria-label={t('expand')} />
|
|
204
198
|
</label>
|
|
199
|
+
|
|
205
200
|
<aside
|
|
206
201
|
className={`memori-sidebar ${
|
|
207
202
|
fullScreen ? 'memori-sidebar-fullscreen' : ''
|
|
@@ -9,7 +9,19 @@
|
|
|
9
9
|
.memori-sidebar-toggle {
|
|
10
10
|
display: none;
|
|
11
11
|
}
|
|
12
|
+
.memori-chat--content{
|
|
13
|
+
padding: 0;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.memori-chat-inputs{
|
|
17
|
+
padding: 8px 24px;
|
|
18
|
+
}
|
|
12
19
|
|
|
20
|
+
.memori-chat-history{
|
|
21
|
+
height: calc(100% - 75px);
|
|
22
|
+
margin: 0;
|
|
23
|
+
}
|
|
24
|
+
/* Modern floating toggle button */
|
|
13
25
|
.memori-sidebar-toggle-label {
|
|
14
26
|
position: absolute;
|
|
15
27
|
top: 50%;
|
|
@@ -19,7 +31,7 @@
|
|
|
19
31
|
height: 80px;
|
|
20
32
|
align-items: center;
|
|
21
33
|
justify-content: center;
|
|
22
|
-
padding:
|
|
34
|
+
padding: 12px 8px;
|
|
23
35
|
background-color: var(--memori-primary);
|
|
24
36
|
color: white;
|
|
25
37
|
cursor: pointer;
|
|
@@ -37,10 +49,9 @@
|
|
|
37
49
|
|
|
38
50
|
.memori-close-label {
|
|
39
51
|
right: 350px;
|
|
40
|
-
border-radius: 0
|
|
52
|
+
border-radius: 5px 0 0 5px;
|
|
41
53
|
opacity: 0;
|
|
42
54
|
pointer-events: none;
|
|
43
|
-
transform: rotate(180deg);
|
|
44
55
|
transition: opacity 0.3s ease-in-out, transform 0.3s ease-in-out, right 0.3s ease-in-out;
|
|
45
56
|
}
|
|
46
57
|
|
package/src/helpers/utils.ts
CHANGED
|
@@ -232,7 +232,7 @@ export const stripReasoningTags = (text: string) => {
|
|
|
232
232
|
const strippedText = text.replace(reasoningTagRegex, '');
|
|
233
233
|
|
|
234
234
|
// Recursively strip nested reasoning tags
|
|
235
|
-
return
|
|
235
|
+
return strippedText;
|
|
236
236
|
};
|
|
237
237
|
|
|
238
238
|
export const stripHTML = (text: string) => {
|
|
@@ -1,325 +0,0 @@
|
|
|
1
|
-
import { User, Tenant } from '@memori.ai/memori-api-client/dist/types';
|
|
2
|
-
import React, { useEffect, useState } from 'react';
|
|
3
|
-
import Button from '../ui/Button';
|
|
4
|
-
import { useTranslation } from 'react-i18next';
|
|
5
|
-
import memoriApiClient from '@memori.ai/memori-api-client';
|
|
6
|
-
import toast from 'react-hot-toast';
|
|
7
|
-
import { mailRegEx, pwdRegEx, usernameRegEx } from '../../helpers/utils';
|
|
8
|
-
import { getErrori18nKey } from '../../helpers/error';
|
|
9
|
-
import Tooltip from '../ui/Tooltip';
|
|
10
|
-
|
|
11
|
-
export interface Props {
|
|
12
|
-
user: User;
|
|
13
|
-
loginToken: string;
|
|
14
|
-
apiClient: ReturnType<typeof memoriApiClient>;
|
|
15
|
-
onUserUpdate: (user: User) => void;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const imgMimeTypes = ['image/jpeg', 'image/png', 'image/jpg', 'image/gif'];
|
|
19
|
-
|
|
20
|
-
const AccountForm = ({ user, loginToken, apiClient, onUserUpdate }: Props) => {
|
|
21
|
-
const { t, i18n } = useTranslation();
|
|
22
|
-
const lang = i18n.language === 'it' ? 'it' : 'en';
|
|
23
|
-
|
|
24
|
-
const { updateUser, uploadAsset } = apiClient.backend;
|
|
25
|
-
|
|
26
|
-
const [email, setEmail] = useState<string>();
|
|
27
|
-
const [password, setPassword] = useState<string>();
|
|
28
|
-
const [confirmPassword, setConfirmPassword] = useState<string>();
|
|
29
|
-
|
|
30
|
-
const pwdAcceptable = !password || (password && pwdRegEx.test(password));
|
|
31
|
-
const pwdGreen = pwdAcceptable && password && password.length >= 24;
|
|
32
|
-
const pwdEmpty = !password || password.length === 0;
|
|
33
|
-
const pwdMeterValue =
|
|
34
|
-
!pwdAcceptable || pwdEmpty
|
|
35
|
-
? 0
|
|
36
|
-
: password.length < 8
|
|
37
|
-
? 15
|
|
38
|
-
: password.length >= 32
|
|
39
|
-
? 100
|
|
40
|
-
: (password.length - 8) * (50 / 24) + 50;
|
|
41
|
-
|
|
42
|
-
const [loading, setLoading] = useState(false);
|
|
43
|
-
const [error, setError] = useState<string | null>(null);
|
|
44
|
-
|
|
45
|
-
const sendUserUpdate = async (userID: string, user: Partial<User>) => {
|
|
46
|
-
try {
|
|
47
|
-
const { user: updatedUser, ...resp } = await updateUser(
|
|
48
|
-
loginToken,
|
|
49
|
-
userID,
|
|
50
|
-
user
|
|
51
|
-
);
|
|
52
|
-
|
|
53
|
-
if (resp.resultCode !== 0) {
|
|
54
|
-
console.error(resp);
|
|
55
|
-
toast.error(t(getErrori18nKey(resp.resultCode)));
|
|
56
|
-
} else if (updatedUser) {
|
|
57
|
-
toast.success(t('success'));
|
|
58
|
-
onUserUpdate(updatedUser);
|
|
59
|
-
}
|
|
60
|
-
} catch (e) {
|
|
61
|
-
let err = e as Error;
|
|
62
|
-
console.error('[signup]', err);
|
|
63
|
-
if (err?.message) toast.error(err.message);
|
|
64
|
-
} finally {
|
|
65
|
-
setLoading(false);
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
const submitUserUpdate = async (e: React.FormEvent<HTMLFormElement>) => {
|
|
70
|
-
e.preventDefault();
|
|
71
|
-
if (!user.userID) return;
|
|
72
|
-
const userID = user.userID;
|
|
73
|
-
|
|
74
|
-
const form = e.currentTarget as HTMLFormElement;
|
|
75
|
-
|
|
76
|
-
const eMail = form.eMail.value ?? email;
|
|
77
|
-
const newPassword = form.newPassword.value ?? password;
|
|
78
|
-
const currentPassword = form.password.value;
|
|
79
|
-
const confirmPassword = form.confirmPassword.value;
|
|
80
|
-
const pAndCUAccepted = (form.pAndCUAccepted as HTMLInputElement | null)
|
|
81
|
-
?.checked;
|
|
82
|
-
const avatar = (form.avatar as HTMLInputElement | null)?.files?.[0];
|
|
83
|
-
|
|
84
|
-
setLoading(true);
|
|
85
|
-
setError(null);
|
|
86
|
-
|
|
87
|
-
if (newPassword?.length && newPassword !== confirmPassword) {
|
|
88
|
-
setError(t('login.passwordMatchingError'));
|
|
89
|
-
setLoading(false);
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
let patchedUser: User = {
|
|
94
|
-
...(eMail?.length && eMail !== user.eMail ? { eMail } : {}),
|
|
95
|
-
...(newPassword ? { password: currentPassword, newPassword } : {}),
|
|
96
|
-
...(pAndCUAccepted !== undefined && pAndCUAccepted !== user.pAndCUAccepted
|
|
97
|
-
? { pAndCUAccepted, pAndCUAcceptanceDate: new Date().toISOString() }
|
|
98
|
-
: {}),
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
if (Object.values(patchedUser).length === 0 && !avatar) {
|
|
102
|
-
console.debug('No changes to submit');
|
|
103
|
-
setLoading(false);
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (avatar) {
|
|
108
|
-
const reader = new FileReader();
|
|
109
|
-
reader.onload = async e => {
|
|
110
|
-
try {
|
|
111
|
-
const { asset: avatarAsset, ...resp } = await uploadAsset(
|
|
112
|
-
avatar.name ?? 'avatar',
|
|
113
|
-
e.target?.result as string,
|
|
114
|
-
loginToken
|
|
115
|
-
);
|
|
116
|
-
|
|
117
|
-
if (resp.resultCode !== 0) {
|
|
118
|
-
console.error(resp);
|
|
119
|
-
toast.error(t(getErrori18nKey(resp.resultCode)));
|
|
120
|
-
} else if (avatarAsset) {
|
|
121
|
-
patchedUser.avatarURL = avatarAsset.assetURL;
|
|
122
|
-
|
|
123
|
-
await sendUserUpdate(userID, patchedUser);
|
|
124
|
-
}
|
|
125
|
-
} catch (e) {
|
|
126
|
-
let err = e as Error;
|
|
127
|
-
console.error('[avatar upload]', err);
|
|
128
|
-
|
|
129
|
-
if (err?.message) toast.error(err.message);
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
reader.readAsDataURL(avatar);
|
|
133
|
-
} else {
|
|
134
|
-
await sendUserUpdate(userID, patchedUser);
|
|
135
|
-
}
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
return (
|
|
139
|
-
<>
|
|
140
|
-
<h3 className="memori--login-drawer--edit-account-title">
|
|
141
|
-
{t('login.editAccount')}
|
|
142
|
-
</h3>
|
|
143
|
-
|
|
144
|
-
<form
|
|
145
|
-
className="memori--login-drawer--form memori--login-drawer--account-form"
|
|
146
|
-
onSubmit={submitUserUpdate}
|
|
147
|
-
>
|
|
148
|
-
<details className="memori--details">
|
|
149
|
-
<summary>{t('login.emailChange')}</summary>
|
|
150
|
-
|
|
151
|
-
<label htmlFor="#eMail">
|
|
152
|
-
{t('login.email')}
|
|
153
|
-
<input
|
|
154
|
-
type="email"
|
|
155
|
-
name="eMail"
|
|
156
|
-
id="eMail"
|
|
157
|
-
autoComplete="email"
|
|
158
|
-
placeholder={user.eMail}
|
|
159
|
-
onChange={e => setEmail(e.target.value)}
|
|
160
|
-
aria-invalid={!!email?.length && !mailRegEx.test(email)}
|
|
161
|
-
/>
|
|
162
|
-
</label>
|
|
163
|
-
{!!email?.length && !mailRegEx.test(email) && (
|
|
164
|
-
<p className="memori--login-drawer--inline-error">
|
|
165
|
-
{t('login.emailFormatError')}
|
|
166
|
-
</p>
|
|
167
|
-
)}
|
|
168
|
-
</details>
|
|
169
|
-
|
|
170
|
-
<details className="memori--details">
|
|
171
|
-
<summary>{t('login.passwordChange')}</summary>
|
|
172
|
-
|
|
173
|
-
<label htmlFor="#password">
|
|
174
|
-
{t('login.currentPassword')}
|
|
175
|
-
<input
|
|
176
|
-
id="password"
|
|
177
|
-
name="password"
|
|
178
|
-
type="password"
|
|
179
|
-
autoComplete="password"
|
|
180
|
-
placeholder={t('login.currentPassword') || 'Password'}
|
|
181
|
-
/>
|
|
182
|
-
</label>
|
|
183
|
-
|
|
184
|
-
<label htmlFor="#newPassword">
|
|
185
|
-
{t('login.newPassword')}
|
|
186
|
-
<input
|
|
187
|
-
id="newPassword"
|
|
188
|
-
name="newPassword"
|
|
189
|
-
type="password"
|
|
190
|
-
autoComplete="new-password"
|
|
191
|
-
placeholder={t('login.password') || 'Password'}
|
|
192
|
-
onChange={e => setPassword(e.target.value)}
|
|
193
|
-
aria-invalid={!pwdAcceptable}
|
|
194
|
-
/>
|
|
195
|
-
</label>
|
|
196
|
-
{!pwdAcceptable && (
|
|
197
|
-
<p className="memori--login-drawer--inline-error">
|
|
198
|
-
{t('login.passwordFormatError')}
|
|
199
|
-
</p>
|
|
200
|
-
)}
|
|
201
|
-
|
|
202
|
-
<label htmlFor="#confirm-password">
|
|
203
|
-
{t('login.confirmPassword')}
|
|
204
|
-
<input
|
|
205
|
-
id="confirm-password"
|
|
206
|
-
name="confirmPassword"
|
|
207
|
-
type="password"
|
|
208
|
-
autoComplete="new-password"
|
|
209
|
-
placeholder={t('login.confirmPassword') || 'Password'}
|
|
210
|
-
onChange={e => setConfirmPassword(e.target.value)}
|
|
211
|
-
aria-invalid={
|
|
212
|
-
!!password?.length &&
|
|
213
|
-
!!confirmPassword?.length &&
|
|
214
|
-
password !== confirmPassword
|
|
215
|
-
}
|
|
216
|
-
/>
|
|
217
|
-
</label>
|
|
218
|
-
{!!password?.length &&
|
|
219
|
-
!!confirmPassword?.length &&
|
|
220
|
-
password !== confirmPassword && (
|
|
221
|
-
<p className="memori--login-drawer--inline-error">
|
|
222
|
-
{t('login.passwordMatchingError')}
|
|
223
|
-
</p>
|
|
224
|
-
)}
|
|
225
|
-
|
|
226
|
-
<meter
|
|
227
|
-
className="memori--login-drawer--password-meter"
|
|
228
|
-
min={0}
|
|
229
|
-
low={33}
|
|
230
|
-
high={66}
|
|
231
|
-
optimum={80}
|
|
232
|
-
max={100}
|
|
233
|
-
value={pwdMeterValue}
|
|
234
|
-
id="password-strength-meter"
|
|
235
|
-
/>
|
|
236
|
-
<small>
|
|
237
|
-
{t(
|
|
238
|
-
`login.pwd${
|
|
239
|
-
pwdGreen ? 'Strong' : pwdAcceptable ? 'Acceptable' : 'Weak'
|
|
240
|
-
}`
|
|
241
|
-
)}
|
|
242
|
-
</small>
|
|
243
|
-
</details>
|
|
244
|
-
|
|
245
|
-
<details className="memori--details">
|
|
246
|
-
<summary>{t('login.avatarChange')}</summary>
|
|
247
|
-
|
|
248
|
-
<label htmlFor="#avatar">
|
|
249
|
-
Avatar
|
|
250
|
-
<input
|
|
251
|
-
type="file"
|
|
252
|
-
name="avatar"
|
|
253
|
-
id="avatar"
|
|
254
|
-
accept={imgMimeTypes.join(', ')}
|
|
255
|
-
placeholder={user.avatarURL}
|
|
256
|
-
/>
|
|
257
|
-
</label>
|
|
258
|
-
</details>
|
|
259
|
-
|
|
260
|
-
<label className="memori-checkbox memori-checkbox--disabled">
|
|
261
|
-
<span className="memori-checkbox--input-wrapper">
|
|
262
|
-
<input
|
|
263
|
-
type="checkbox"
|
|
264
|
-
name="tnCAndPPAccepted"
|
|
265
|
-
disabled
|
|
266
|
-
defaultChecked={user.tnCAndPPAccepted}
|
|
267
|
-
checked={user.tnCAndPPAccepted}
|
|
268
|
-
className="memori-checkbox--input"
|
|
269
|
-
/>
|
|
270
|
-
<span className="memori-checkbox--inner" />
|
|
271
|
-
</span>
|
|
272
|
-
<span className="memori-checkbox--text">
|
|
273
|
-
{t('login.privacyLabel')}{' '}
|
|
274
|
-
<a
|
|
275
|
-
href={`https://memori.ai/${lang}/privacy_and_cookie`}
|
|
276
|
-
target="_blank"
|
|
277
|
-
rel="noopener noreferrer"
|
|
278
|
-
>
|
|
279
|
-
{t('login.privacyAndCookiePolicy')}
|
|
280
|
-
</a>{' '}
|
|
281
|
-
{t('login.and')}{' '}
|
|
282
|
-
<a
|
|
283
|
-
href={`https://memori.ai/${lang}/tos`}
|
|
284
|
-
target="_blank"
|
|
285
|
-
rel="noopener noreferrer"
|
|
286
|
-
>
|
|
287
|
-
{t('login.termsOfService')}
|
|
288
|
-
</a>
|
|
289
|
-
</span>
|
|
290
|
-
</label>
|
|
291
|
-
|
|
292
|
-
<label className="memori-checkbox">
|
|
293
|
-
<span className="memori-checkbox--input-wrapper">
|
|
294
|
-
<input
|
|
295
|
-
type="checkbox"
|
|
296
|
-
name="pAndCUAccepted"
|
|
297
|
-
className="memori-checkbox--input"
|
|
298
|
-
defaultChecked={user.pAndCUAccepted}
|
|
299
|
-
/>
|
|
300
|
-
<span className="memori-checkbox--inner" />
|
|
301
|
-
</span>
|
|
302
|
-
<Tooltip align="left" content={t('login.deepThoughtExplaination')}>
|
|
303
|
-
<span className="memori-checkbox--text">
|
|
304
|
-
{t('login.pAndCUAccepted')}{' '}
|
|
305
|
-
<small>
|
|
306
|
-
<em>({t('login.optional')})</em>
|
|
307
|
-
</small>
|
|
308
|
-
</span>
|
|
309
|
-
</Tooltip>
|
|
310
|
-
</label>
|
|
311
|
-
|
|
312
|
-
<Button htmlType="submit" primary loading={loading}>
|
|
313
|
-
{t('login.save')}
|
|
314
|
-
</Button>
|
|
315
|
-
</form>
|
|
316
|
-
{error && (
|
|
317
|
-
<p role="alert" className="memori--login-drawer--error">
|
|
318
|
-
{error}
|
|
319
|
-
</p>
|
|
320
|
-
)}
|
|
321
|
-
</>
|
|
322
|
-
);
|
|
323
|
-
};
|
|
324
|
-
|
|
325
|
-
export default AccountForm;
|