@memori.ai/memori-react 6.4.5 → 6.5.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.
Files changed (83) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/dist/components/AccountForm/AccountForm.d.ts +9 -0
  3. package/dist/components/AccountForm/AccountForm.js +122 -0
  4. package/dist/components/AccountForm/AccountForm.js.map +1 -0
  5. package/dist/components/Chat/Chat.d.ts +1 -0
  6. package/dist/components/Chat/Chat.js +2 -2
  7. package/dist/components/Chat/Chat.js.map +1 -1
  8. package/dist/components/LoginDrawer/LoginDrawer.css +59 -3
  9. package/dist/components/LoginDrawer/LoginDrawer.d.ts +4 -2
  10. package/dist/components/LoginDrawer/LoginDrawer.js +110 -25
  11. package/dist/components/LoginDrawer/LoginDrawer.js.map +1 -1
  12. package/dist/components/MemoriWidget/MemoriWidget.js +10 -0
  13. package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
  14. package/dist/components/SignupForm/SignupForm.d.ts +10 -0
  15. package/dist/components/SignupForm/SignupForm.js +201 -0
  16. package/dist/components/SignupForm/SignupForm.js.map +1 -0
  17. package/dist/components/VenueWidget/VenueWidget.css +14 -0
  18. package/dist/components/ui/Checkbox.css +2 -4
  19. package/dist/components/ui/Details.css +66 -0
  20. package/dist/helpers/constants.js +1 -0
  21. package/dist/helpers/constants.js.map +1 -1
  22. package/dist/helpers/error.js +4 -0
  23. package/dist/helpers/error.js.map +1 -1
  24. package/dist/helpers/utils.js +3 -3
  25. package/dist/helpers/utils.js.map +1 -1
  26. package/dist/locales/en.json +29 -0
  27. package/dist/locales/it.json +31 -2
  28. package/dist/styles.css +5 -3
  29. package/esm/components/AccountForm/AccountForm.d.ts +9 -0
  30. package/esm/components/AccountForm/AccountForm.js +119 -0
  31. package/esm/components/AccountForm/AccountForm.js.map +1 -0
  32. package/esm/components/Chat/Chat.d.ts +1 -0
  33. package/esm/components/Chat/Chat.js +2 -2
  34. package/esm/components/Chat/Chat.js.map +1 -1
  35. package/esm/components/LoginDrawer/LoginDrawer.css +59 -3
  36. package/esm/components/LoginDrawer/LoginDrawer.d.ts +4 -2
  37. package/esm/components/LoginDrawer/LoginDrawer.js +110 -24
  38. package/esm/components/LoginDrawer/LoginDrawer.js.map +1 -1
  39. package/esm/components/MemoriWidget/MemoriWidget.js +10 -0
  40. package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
  41. package/esm/components/SignupForm/SignupForm.d.ts +10 -0
  42. package/esm/components/SignupForm/SignupForm.js +198 -0
  43. package/esm/components/SignupForm/SignupForm.js.map +1 -0
  44. package/esm/components/VenueWidget/VenueWidget.css +14 -0
  45. package/esm/components/ui/Checkbox.css +2 -4
  46. package/esm/components/ui/Details.css +66 -0
  47. package/esm/helpers/constants.js +1 -0
  48. package/esm/helpers/constants.js.map +1 -1
  49. package/esm/helpers/error.js +4 -0
  50. package/esm/helpers/error.js.map +1 -1
  51. package/esm/helpers/utils.js +3 -3
  52. package/esm/helpers/utils.js.map +1 -1
  53. package/esm/locales/en.json +29 -0
  54. package/esm/locales/it.json +31 -2
  55. package/esm/styles.css +5 -3
  56. package/package.json +1 -1
  57. package/src/components/AccountForm/AccountForm.test.tsx +26 -0
  58. package/src/components/AccountForm/AccountForm.tsx +326 -0
  59. package/src/components/AccountForm/__snapshots__/AccountForm.test.tsx.snap +202 -0
  60. package/src/components/Chat/Chat.tsx +3 -0
  61. package/src/components/LoginDrawer/LoginDrawer.css +59 -3
  62. package/src/components/LoginDrawer/LoginDrawer.stories.tsx +19 -0
  63. package/src/components/LoginDrawer/LoginDrawer.test.tsx +48 -2
  64. package/src/components/LoginDrawer/LoginDrawer.tsx +233 -25
  65. package/src/components/LoginDrawer/__snapshots__/LoginDrawer.test.tsx.snap +24 -0
  66. package/src/components/MemoriWidget/MemoriWidget.tsx +15 -0
  67. package/src/components/SignupForm/SignupForm.test.tsx +39 -0
  68. package/src/components/SignupForm/SignupForm.tsx +458 -0
  69. package/src/components/SignupForm/__snapshots__/SignupForm.test.tsx.snap +247 -0
  70. package/src/components/StartPanel/__snapshots__/StartPanel.test.tsx.snap +6 -0
  71. package/src/components/VenueWidget/VenueWidget.css +14 -0
  72. package/src/components/layouts/__snapshots__/Chat.test.tsx.snap +6 -0
  73. package/src/components/layouts/__snapshots__/FullPage.test.tsx.snap +6 -0
  74. package/src/components/layouts/__snapshots__/Totem.test.tsx.snap +6 -0
  75. package/src/components/ui/Checkbox.css +2 -4
  76. package/src/components/ui/Details.css +66 -0
  77. package/src/helpers/constants.ts +1 -0
  78. package/src/helpers/error.ts +4 -0
  79. package/src/helpers/utils.ts +4 -3
  80. package/src/locales/en.json +29 -0
  81. package/src/locales/it.json +32 -3
  82. package/src/mocks/data.ts +1 -0
  83. package/src/styles.css +5 -3
@@ -0,0 +1,326 @@
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
+ apiUrl: string;
15
+ onUserUpdate: (user: User) => void;
16
+ }
17
+
18
+ const imgMimeTypes = ['image/jpeg', 'image/png', 'image/jpg', 'image/gif'];
19
+
20
+ const AccountForm = ({ user, loginToken, apiUrl, onUserUpdate }: Props) => {
21
+ const { t, i18n } = useTranslation();
22
+ const lang = i18n.language === 'it' ? 'it' : 'en';
23
+
24
+ const client = memoriApiClient(apiUrl);
25
+
26
+ const { updateUser, uploadAsset } = client.backend;
27
+
28
+ const [email, setEmail] = useState<string>();
29
+ const [password, setPassword] = useState<string>();
30
+ const [confirmPassword, setConfirmPassword] = useState<string>();
31
+
32
+ const pwdAcceptable = !password || (password && pwdRegEx.test(password));
33
+ const pwdGreen = pwdAcceptable && password && password.length >= 24;
34
+ const pwdEmpty = !password || password.length === 0;
35
+ const pwdMeterValue =
36
+ !pwdAcceptable || pwdEmpty
37
+ ? 0
38
+ : password.length < 8
39
+ ? 15
40
+ : password.length >= 32
41
+ ? 100
42
+ : (password.length - 8) * (50 / 24) + 50;
43
+
44
+ const [loading, setLoading] = useState(false);
45
+ const [error, setError] = useState<string | null>(null);
46
+
47
+ const sendUserUpdate = async (userID: string, user: Partial<User>) => {
48
+ try {
49
+ const { user: updatedUser, ...resp } = await updateUser(
50
+ loginToken,
51
+ userID,
52
+ user
53
+ );
54
+
55
+ if (resp.resultCode !== 0) {
56
+ console.error(resp);
57
+ toast.error(t(getErrori18nKey(resp.resultCode)));
58
+ } else if (updatedUser) {
59
+ toast.success(t('success'));
60
+ onUserUpdate(updatedUser);
61
+ }
62
+ } catch (e) {
63
+ let err = e as Error;
64
+ console.error('[signup]', err);
65
+ if (err?.message) toast.error(err.message);
66
+ } finally {
67
+ setLoading(false);
68
+ }
69
+ };
70
+
71
+ const submitUserUpdate = async (e: React.FormEvent<HTMLFormElement>) => {
72
+ e.preventDefault();
73
+ if (!user.userID) return;
74
+ const userID = user.userID;
75
+
76
+ const form = e.currentTarget as HTMLFormElement;
77
+
78
+ const eMail = form.eMail.value ?? email;
79
+ const newPassword = form.newPassword.value ?? password;
80
+ const currentPassword = form.password.value;
81
+ const confirmPassword = form.confirmPassword.value;
82
+ const pAndCUAccepted = (form.pAndCUAccepted as HTMLInputElement | null)
83
+ ?.checked;
84
+ const avatar = (form.avatar as HTMLInputElement | null)?.files?.[0];
85
+
86
+ setLoading(true);
87
+ setError(null);
88
+
89
+ if (newPassword?.length && newPassword !== confirmPassword) {
90
+ setError(t('login.passwordMatchingError'));
91
+ setLoading(false);
92
+ return;
93
+ }
94
+
95
+ let patchedUser: User = {
96
+ ...(eMail?.length && eMail !== user.eMail ? { eMail } : {}),
97
+ ...(newPassword ? { password: currentPassword, newPassword } : {}),
98
+ ...(pAndCUAccepted !== undefined && pAndCUAccepted !== user.pAndCUAccepted
99
+ ? { pAndCUAccepted, pAndCUAcceptanceDate: new Date().toISOString() }
100
+ : {}),
101
+ };
102
+
103
+ if (Object.values(patchedUser).length === 0) {
104
+ console.debug('No changes to submit');
105
+ return;
106
+ }
107
+
108
+ if (avatar) {
109
+ const reader = new FileReader();
110
+ reader.onload = async e => {
111
+ try {
112
+ const { asset: avatarAsset, ...resp } = await uploadAsset(
113
+ avatar.name ?? 'avatar',
114
+ e.target?.result as string,
115
+ loginToken
116
+ );
117
+
118
+ if (resp.resultCode !== 0) {
119
+ console.error(resp);
120
+ toast.error(t(getErrori18nKey(resp.resultCode)));
121
+ } else if (avatarAsset) {
122
+ patchedUser.avatarURL = avatarAsset.assetURL;
123
+
124
+ await sendUserUpdate(userID, patchedUser);
125
+ }
126
+ } catch (e) {
127
+ let err = e as Error;
128
+ console.error('[avatar upload]', err);
129
+
130
+ if (err?.message) toast.error(err.message);
131
+ }
132
+ };
133
+ reader.readAsDataURL(avatar);
134
+ } else {
135
+ await sendUserUpdate(userID, patchedUser);
136
+ }
137
+ };
138
+
139
+ return (
140
+ <>
141
+ <h3 className="memori--login-drawer--edit-account-title">
142
+ {t('login.editAccount')}
143
+ </h3>
144
+
145
+ <form
146
+ className="memori--login-drawer--form memori--login-drawer--account-form"
147
+ onSubmit={submitUserUpdate}
148
+ >
149
+ <details className="memori--details">
150
+ <summary>{t('login.emailChange')}</summary>
151
+
152
+ <label htmlFor="#eMail">
153
+ {t('login.email')}
154
+ <input
155
+ type="email"
156
+ name="eMail"
157
+ id="eMail"
158
+ autoComplete="email"
159
+ placeholder={user.eMail}
160
+ onChange={e => setEmail(e.target.value)}
161
+ aria-invalid={!!email?.length && !mailRegEx.test(email)}
162
+ />
163
+ </label>
164
+ {!!email?.length && !mailRegEx.test(email) && (
165
+ <p className="memori--login-drawer--inline-error">
166
+ {t('login.emailFormatError')}
167
+ </p>
168
+ )}
169
+ </details>
170
+
171
+ <details className="memori--details">
172
+ <summary>{t('login.passwordChange')}</summary>
173
+
174
+ <label htmlFor="#password">
175
+ {t('login.currentPassword')}
176
+ <input
177
+ id="password"
178
+ name="password"
179
+ type="password"
180
+ autoComplete="password"
181
+ placeholder={t('login.currentPassword') || 'Password'}
182
+ />
183
+ </label>
184
+
185
+ <label htmlFor="#newPassword">
186
+ {t('login.newPassword')}
187
+ <input
188
+ id="newPassword"
189
+ name="newPassword"
190
+ type="password"
191
+ autoComplete="new-password"
192
+ placeholder={t('login.password') || 'Password'}
193
+ onChange={e => setPassword(e.target.value)}
194
+ aria-invalid={!pwdAcceptable}
195
+ />
196
+ </label>
197
+ {!pwdAcceptable && (
198
+ <p className="memori--login-drawer--inline-error">
199
+ {t('login.passwordFormatError')}
200
+ </p>
201
+ )}
202
+
203
+ <label htmlFor="#confirm-password">
204
+ {t('login.confirmPassword')}
205
+ <input
206
+ id="confirm-password"
207
+ name="confirmPassword"
208
+ type="password"
209
+ autoComplete="new-password"
210
+ placeholder={t('login.confirmPassword') || 'Password'}
211
+ onChange={e => setConfirmPassword(e.target.value)}
212
+ aria-invalid={
213
+ !!password?.length &&
214
+ !!confirmPassword?.length &&
215
+ password !== confirmPassword
216
+ }
217
+ />
218
+ </label>
219
+ {!!password?.length &&
220
+ !!confirmPassword?.length &&
221
+ password !== confirmPassword && (
222
+ <p className="memori--login-drawer--inline-error">
223
+ {t('login.passwordMatchingError')}
224
+ </p>
225
+ )}
226
+
227
+ <meter
228
+ className="memori--login-drawer--password-meter"
229
+ min={0}
230
+ low={33}
231
+ high={66}
232
+ optimum={80}
233
+ max={100}
234
+ value={pwdMeterValue}
235
+ id="password-strength-meter"
236
+ />
237
+ <small>
238
+ {t(
239
+ `login.pwd${
240
+ pwdGreen ? 'Strong' : pwdAcceptable ? 'Acceptable' : 'Weak'
241
+ }`
242
+ )}
243
+ </small>
244
+ </details>
245
+
246
+ <details className="memori--details">
247
+ <summary>{t('login.avatarChange')}</summary>
248
+
249
+ <label htmlFor="#avatar">
250
+ Avatar
251
+ <input
252
+ type="file"
253
+ name="avatar"
254
+ id="avatar"
255
+ accept={imgMimeTypes.join(', ')}
256
+ placeholder={user.avatarURL}
257
+ />
258
+ </label>
259
+ </details>
260
+
261
+ <label className="memori-checkbox memori-checkbox--disabled">
262
+ <span className="memori-checkbox--input-wrapper">
263
+ <input
264
+ type="checkbox"
265
+ name="tnCAndPPAccepted"
266
+ disabled
267
+ defaultChecked={user.tnCAndPPAccepted}
268
+ checked={user.tnCAndPPAccepted}
269
+ className="memori-checkbox--input"
270
+ />
271
+ <span className="memori-checkbox--inner" />
272
+ </span>
273
+ <span className="memori-checkbox--text">
274
+ {t('login.privacyLabel')}{' '}
275
+ <a
276
+ href={`https://memori.ai/${lang}/privacy_and_cookie`}
277
+ target="_blank"
278
+ rel="noopener noreferrer"
279
+ >
280
+ {t('login.privacyAndCookiePolicy')}
281
+ </a>{' '}
282
+ {t('login.and')}{' '}
283
+ <a
284
+ href={`https://memori.ai/${lang}/tos`}
285
+ target="_blank"
286
+ rel="noopener noreferrer"
287
+ >
288
+ {t('login.termsOfService')}
289
+ </a>
290
+ </span>
291
+ </label>
292
+
293
+ <label className="memori-checkbox">
294
+ <span className="memori-checkbox--input-wrapper">
295
+ <input
296
+ type="checkbox"
297
+ name="pAndCUAccepted"
298
+ className="memori-checkbox--input"
299
+ defaultChecked={user.pAndCUAccepted}
300
+ />
301
+ <span className="memori-checkbox--inner" />
302
+ </span>
303
+ <Tooltip align="left" content={t('login.deepThoughtExplaination')}>
304
+ <span className="memori-checkbox--text">
305
+ {t('login.pAndCUAccepted')}{' '}
306
+ <small>
307
+ <em>({t('login.optional')})</em>
308
+ </small>
309
+ </span>
310
+ </Tooltip>
311
+ </label>
312
+
313
+ <Button htmlType="submit" primary loading={loading}>
314
+ {t('login.save')}
315
+ </Button>
316
+ </form>
317
+ {error && (
318
+ <p role="alert" className="memori--login-drawer--error">
319
+ {error}
320
+ </p>
321
+ )}
322
+ </>
323
+ );
324
+ };
325
+
326
+ export default AccountForm;
@@ -0,0 +1,202 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`renders AccountForm unchanged 1`] = `
4
+ <div>
5
+ <h3
6
+ class="memori--login-drawer--edit-account-title"
7
+ >
8
+ login.editAccount
9
+ </h3>
10
+ <form
11
+ class="memori--login-drawer--form memori--login-drawer--account-form"
12
+ >
13
+ <details
14
+ class="memori--details"
15
+ >
16
+ <summary>
17
+ login.emailChange
18
+ </summary>
19
+ <label
20
+ for="#eMail"
21
+ >
22
+ login.email
23
+ <input
24
+ aria-invalid="false"
25
+ autocomplete="email"
26
+ id="eMail"
27
+ name="eMail"
28
+ placeholder="nicola@nzambello.dev"
29
+ type="email"
30
+ />
31
+ </label>
32
+ </details>
33
+ <details
34
+ class="memori--details"
35
+ >
36
+ <summary>
37
+ login.passwordChange
38
+ </summary>
39
+ <label
40
+ for="#password"
41
+ >
42
+ login.currentPassword
43
+ <input
44
+ autocomplete="password"
45
+ id="password"
46
+ name="password"
47
+ placeholder="login.currentPassword"
48
+ type="password"
49
+ />
50
+ </label>
51
+ <label
52
+ for="#newPassword"
53
+ >
54
+ login.newPassword
55
+ <input
56
+ aria-invalid="false"
57
+ autocomplete="new-password"
58
+ id="newPassword"
59
+ name="newPassword"
60
+ placeholder="login.password"
61
+ type="password"
62
+ />
63
+ </label>
64
+ <label
65
+ for="#confirm-password"
66
+ >
67
+ login.confirmPassword
68
+ <input
69
+ aria-invalid="false"
70
+ autocomplete="new-password"
71
+ id="confirm-password"
72
+ name="confirmPassword"
73
+ placeholder="login.confirmPassword"
74
+ type="password"
75
+ />
76
+ </label>
77
+ <meter
78
+ class="memori--login-drawer--password-meter"
79
+ high="66"
80
+ id="password-strength-meter"
81
+ low="33"
82
+ max="100"
83
+ min="0"
84
+ optimum="80"
85
+ value="0"
86
+ />
87
+ <small>
88
+ login.pwdAcceptable
89
+ </small>
90
+ </details>
91
+ <details
92
+ class="memori--details"
93
+ >
94
+ <summary>
95
+ login.avatarChange
96
+ </summary>
97
+ <label
98
+ for="#avatar"
99
+ >
100
+ Avatar
101
+ <input
102
+ accept="image/jpeg, image/png, image/jpg, image/gif"
103
+ id="avatar"
104
+ name="avatar"
105
+ placeholder="https://avatars.githubusercontent.com/u/21101435?v=4"
106
+ type="file"
107
+ />
108
+ </label>
109
+ </details>
110
+ <label
111
+ class="memori-checkbox memori-checkbox--disabled"
112
+ >
113
+ <span
114
+ class="memori-checkbox--input-wrapper"
115
+ >
116
+ <input
117
+ checked=""
118
+ class="memori-checkbox--input"
119
+ disabled=""
120
+ name="tnCAndPPAccepted"
121
+ type="checkbox"
122
+ />
123
+ <span
124
+ class="memori-checkbox--inner"
125
+ />
126
+ </span>
127
+ <span
128
+ class="memori-checkbox--text"
129
+ >
130
+ login.privacyLabel
131
+
132
+ <a
133
+ href="https://memori.ai/en/privacy_and_cookie"
134
+ rel="noopener noreferrer"
135
+ target="_blank"
136
+ >
137
+ login.privacyAndCookiePolicy
138
+ </a>
139
+
140
+ login.and
141
+
142
+ <a
143
+ href="https://memori.ai/en/tos"
144
+ rel="noopener noreferrer"
145
+ target="_blank"
146
+ >
147
+ login.termsOfService
148
+ </a>
149
+ </span>
150
+ </label>
151
+ <label
152
+ class="memori-checkbox"
153
+ >
154
+ <span
155
+ class="memori-checkbox--input-wrapper"
156
+ >
157
+ <input
158
+ checked=""
159
+ class="memori-checkbox--input"
160
+ name="pAndCUAccepted"
161
+ type="checkbox"
162
+ />
163
+ <span
164
+ class="memori-checkbox--inner"
165
+ />
166
+ </span>
167
+ <div
168
+ class="memori-tooltip memori-tooltip--align-left"
169
+ >
170
+ <div
171
+ class="memori-tooltip--content"
172
+ >
173
+ login.deepThoughtExplaination
174
+ </div>
175
+ <div
176
+ class="memori-tooltip--trigger"
177
+ >
178
+ <span
179
+ class="memori-checkbox--text"
180
+ >
181
+ login.pAndCUAccepted
182
+
183
+ <small>
184
+ <em>
185
+ (
186
+ login.optional
187
+ )
188
+ </em>
189
+ </small>
190
+ </span>
191
+ </div>
192
+ </div>
193
+ </label>
194
+ <button
195
+ class="memori-button memori-button--primary memori-button--rounded memori-button--padded"
196
+ type="submit"
197
+ >
198
+ login.save
199
+ </button>
200
+ </form>
201
+ </div>
202
+ `;
@@ -40,6 +40,7 @@ export interface Props {
40
40
  showDates?: boolean;
41
41
  showContextPerLine?: boolean;
42
42
  showAIicon?: boolean;
43
+ showWhyThisAnswer?: boolean;
43
44
  client: ReturnType<typeof memoriApiClient>;
44
45
  selectReceiverTag: (tag: string) => Promise<void>;
45
46
  preview?: boolean;
@@ -84,6 +85,7 @@ const Chat: React.FC<Props> = ({
84
85
  showDates = false,
85
86
  showContextPerLine = false,
86
87
  showAIicon = true,
88
+ showWhyThisAnswer = true,
87
89
  selectReceiverTag,
88
90
  preview = false,
89
91
  instruct = false,
@@ -205,6 +207,7 @@ const Chat: React.FC<Props> = ({
205
207
  sessionID={sessionID}
206
208
  simulateUserPrompt={simulateUserPrompt}
207
209
  showAIicon={showAIicon}
210
+ showWhyThisAnswer={showWhyThisAnswer}
208
211
  showFeedback={
209
212
  index === history.length - 1 &&
210
213
  !message.fromUser &&
@@ -1,5 +1,5 @@
1
1
  .memori--login-drawer {
2
- z-index: 1000;
2
+ z-index: 10000;
3
3
  }
4
4
 
5
5
  .memori--login-drawer .memori-drawer--panel {
@@ -14,7 +14,7 @@
14
14
  --memori-drawer--width--lg: 30%;
15
15
  }
16
16
 
17
- h2.memori--login-drawer--title {
17
+ .memori--login-drawer--title {
18
18
  margin: 0;
19
19
  font-size: inherit;
20
20
  font-weight: 400;
@@ -33,6 +33,13 @@ p.memori--login-drawer--error {
33
33
  text-align: center;
34
34
  }
35
35
 
36
+ p.memori--login-drawer--inline-error {
37
+ margin: 0 0 0.5rem;
38
+ color: var(--memori-error-color);
39
+ font-size: 0.875rem;
40
+ text-align: center;
41
+ }
42
+
36
43
  .memori--login-drawer--form label:not(.memori-checkbox) {
37
44
  display: flex;
38
45
  flex-direction: column;
@@ -63,6 +70,10 @@ p.memori--login-drawer--error {
63
70
  outline: none;
64
71
  }
65
72
 
73
+ .memori--login-drawer--form input[aria-invalid="true"] {
74
+ border-color: var(--memori-error-color);
75
+ }
76
+
66
77
  .memori--login-drawer--form a {
67
78
  color: var(--memori-primary);
68
79
  text-decoration: underline;
@@ -79,10 +90,55 @@ p.memori--login-drawer--error {
79
90
  margin-top: 1rem;
80
91
  }
81
92
 
82
- .memori--login-drawer--signup {
93
+ .memori--login-drawer--form small {
94
+ color: #666;
95
+ font-size: 0.8rem;
96
+ }
97
+
98
+ p.memori--login-drawer--signup {
83
99
  margin-top: 1.5rem;
84
100
  }
85
101
 
86
102
  .memori--login-drawer--signup p:not(:last-of-type) {
87
103
  margin-bottom: 0.5rem;
104
+ }
105
+
106
+ .memori--login-drawer--password-meter {
107
+ margin: 0;
108
+ text-align: center;
109
+ }
110
+
111
+ meter.memori--login-drawer--password-meter {
112
+ width: 100%;
113
+ }
114
+
115
+ meter.memori--login-drawer--password-meter+small {
116
+ display: inline-block;
117
+ text-align: center;
118
+ }
119
+
120
+ figure.memori--login-drawer--avatar {
121
+ display: flex;
122
+ overflow: hidden;
123
+ width: 60px;
124
+ height: 60px;
125
+ align-items: center;
126
+ justify-content: center;
127
+ border-radius: 50%;
128
+ margin: 0 0 1rem 1rem;
129
+ float: right;
130
+ }
131
+
132
+ figure.memori--login-drawer--avatar img {
133
+ width: 100%;
134
+ height: 100%;
135
+ object-fit: cover;
136
+ object-position: center;
137
+ }
138
+
139
+ h3.memori--login-drawer--edit-account-title {
140
+ margin: 2.5rem 0 0.5rem;
141
+ font-size: 1.33rem;
142
+ font-weight: 400;
143
+ line-height: 1.2;
88
144
  }
@@ -50,6 +50,25 @@ NeedsMissingData.args = {
50
50
  __TEST__needMissingData: true,
51
51
  };
52
52
 
53
+ export const Signup = Template.bind({});
54
+ Signup.args = {
55
+ open: true,
56
+ __TEST__signup: true,
57
+ };
58
+
59
+ export const SignupWaitingForOtp = Template.bind({});
60
+ SignupWaitingForOtp.args = {
61
+ open: true,
62
+ __TEST__signup: true,
63
+ __TEST__waitingForOtp: true,
64
+ };
65
+
66
+ export const ChangePassword = Template.bind({});
67
+ ChangePassword.args = {
68
+ open: true,
69
+ __TEST__changePwd: true,
70
+ };
71
+
53
72
  export const LoggedIn = Template.bind({});
54
73
  LoggedIn.args = {
55
74
  open: true,