@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.
Files changed (45) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/components/Chat/Chat.js +1 -1
  3. package/dist/components/Chat/Chat.js.map +1 -1
  4. package/dist/components/LoginDrawer/LoginDrawer.d.ts +2 -2
  5. package/dist/components/LoginDrawer/LoginDrawer.js +181 -139
  6. package/dist/components/LoginDrawer/LoginDrawer.js.map +1 -1
  7. package/dist/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.d.ts +2 -2
  8. package/dist/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js +61 -32
  9. package/dist/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js.map +1 -1
  10. package/dist/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.css +1 -1
  11. package/dist/components/MemoriWidget/MemoriWidget.js +4 -94
  12. package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
  13. package/dist/components/layouts/HiddenChat.js +3 -9
  14. package/dist/components/layouts/HiddenChat.js.map +1 -1
  15. package/dist/components/layouts/hidden-chat.css +14 -3
  16. package/dist/helpers/utils.js +1 -1
  17. package/dist/helpers/utils.js.map +1 -1
  18. package/esm/components/Chat/Chat.js +1 -1
  19. package/esm/components/Chat/Chat.js.map +1 -1
  20. package/esm/components/LoginDrawer/LoginDrawer.d.ts +2 -2
  21. package/esm/components/LoginDrawer/LoginDrawer.js +183 -141
  22. package/esm/components/LoginDrawer/LoginDrawer.js.map +1 -1
  23. package/esm/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.d.ts +2 -2
  24. package/esm/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js +62 -33
  25. package/esm/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.js.map +1 -1
  26. package/esm/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.css +1 -1
  27. package/esm/components/MemoriWidget/MemoriWidget.js +4 -94
  28. package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
  29. package/esm/components/layouts/HiddenChat.js +3 -9
  30. package/esm/components/layouts/HiddenChat.js.map +1 -1
  31. package/esm/components/layouts/hidden-chat.css +14 -3
  32. package/esm/helpers/utils.js +1 -1
  33. package/esm/helpers/utils.js.map +1 -1
  34. package/package.json +1 -1
  35. package/src/components/Chat/Chat.tsx +1 -1
  36. package/src/components/LoginDrawer/LoginDrawer.test.tsx +12 -12
  37. package/src/components/LoginDrawer/LoginDrawer.tsx +391 -321
  38. package/src/components/MemoriArtifactSystem/ArtifactDrawer.stories.tsx +96 -179
  39. package/src/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.tsx +88 -39
  40. package/src/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.css +1 -1
  41. package/src/components/MemoriWidget/MemoriWidget.tsx +5 -135
  42. package/src/components/layouts/HiddenChat.tsx +4 -9
  43. package/src/components/layouts/hidden-chat.css +14 -3
  44. package/src/helpers/utils.ts +1 -1
  45. 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
- // setUser={setUser}
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: 10px 5px;
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 5px 5px 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
 
@@ -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 stripOutputTags(strippedText);
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;