@memori.ai/memori-react 5.0.2 → 6.0.0-rc.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/CHANGELOG.md +15 -0
- package/README.md +2 -0
- package/dist/components/Header/Header.css +2 -1
- package/dist/components/Header/Header.d.ts +2 -0
- package/dist/components/Header/Header.js +3 -2
- package/dist/components/Header/Header.js.map +1 -1
- package/dist/components/LoginDrawer/LoginDrawer.css +84 -0
- package/dist/components/LoginDrawer/LoginDrawer.d.ts +15 -0
- package/dist/components/LoginDrawer/LoginDrawer.js +129 -0
- package/dist/components/LoginDrawer/LoginDrawer.js.map +1 -0
- package/dist/components/MemoriWidget/MemoriWidget.d.ts +3 -1
- package/dist/components/MemoriWidget/MemoriWidget.js +36 -8
- package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/dist/components/StartPanel/StartPanel.d.ts +2 -0
- package/dist/components/StartPanel/StartPanel.js +2 -2
- package/dist/components/StartPanel/StartPanel.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/locales/en.json +25 -0
- package/dist/locales/it.json +25 -0
- package/dist/styles.css +1 -0
- package/esm/components/Header/Header.css +2 -1
- package/esm/components/Header/Header.d.ts +2 -0
- package/esm/components/Header/Header.js +3 -2
- package/esm/components/Header/Header.js.map +1 -1
- package/esm/components/LoginDrawer/LoginDrawer.css +84 -0
- package/esm/components/LoginDrawer/LoginDrawer.d.ts +15 -0
- package/esm/components/LoginDrawer/LoginDrawer.js +125 -0
- package/esm/components/LoginDrawer/LoginDrawer.js.map +1 -0
- package/esm/components/MemoriWidget/MemoriWidget.d.ts +3 -1
- package/esm/components/MemoriWidget/MemoriWidget.js +36 -8
- package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/esm/components/StartPanel/StartPanel.d.ts +2 -0
- package/esm/components/StartPanel/StartPanel.js +2 -2
- package/esm/components/StartPanel/StartPanel.js.map +1 -1
- package/esm/index.d.ts +2 -0
- package/esm/index.js +5 -3
- package/esm/index.js.map +1 -1
- package/esm/locales/en.json +25 -0
- package/esm/locales/it.json +25 -0
- package/esm/styles.css +1 -0
- package/package.json +1 -1
- package/src/components/Header/Header.css +2 -1
- package/src/components/Header/Header.stories.tsx +27 -1
- package/src/components/Header/Header.test.tsx +14 -1
- package/src/components/Header/Header.tsx +17 -0
- package/src/components/Header/__snapshots__/Header.test.tsx.snap +260 -0
- package/src/components/LoginDrawer/LoginDrawer.css +84 -0
- package/src/components/LoginDrawer/LoginDrawer.stories.tsx +58 -0
- package/src/components/LoginDrawer/LoginDrawer.test.tsx +86 -0
- package/src/components/LoginDrawer/LoginDrawer.tsx +330 -0
- package/src/components/LoginDrawer/__snapshots__/LoginDrawer.test.tsx.snap +35 -0
- package/src/components/MemoriWidget/MemoriWidget.tsx +53 -7
- package/src/components/StartPanel/StartPanel.stories.tsx +3 -1
- package/src/components/StartPanel/StartPanel.test.tsx +12 -0
- package/src/components/StartPanel/StartPanel.tsx +11 -0
- package/src/components/StartPanel/__snapshots__/StartPanel.test.tsx.snap +7 -0
- package/src/components/layouts/__snapshots__/Chat.test.tsx.snap +20 -0
- package/src/components/layouts/__snapshots__/FullPage.test.tsx.snap +20 -0
- package/src/components/layouts/__snapshots__/Totem.test.tsx.snap +20 -0
- package/src/index.stories.tsx +0 -1
- package/src/index.tsx +8 -0
- package/src/locales/en.json +25 -0
- package/src/locales/it.json +25 -0
- package/src/mocks/data.ts +2 -2
- package/src/styles.css +1 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Meta, Story } from '@storybook/react';
|
|
3
|
+
import I18nWrapper from '../../I18nWrapper';
|
|
4
|
+
import LoginDrawer, { Props } from './LoginDrawer';
|
|
5
|
+
import { tenant, user } from '../../mocks/data';
|
|
6
|
+
import './LoginDrawer.css';
|
|
7
|
+
|
|
8
|
+
const meta: Meta = {
|
|
9
|
+
title: 'Widget/LoginDrawer',
|
|
10
|
+
component: LoginDrawer,
|
|
11
|
+
argTypes: {
|
|
12
|
+
open: {
|
|
13
|
+
control: {
|
|
14
|
+
type: 'boolean',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
parameters: {
|
|
19
|
+
controls: { expanded: true },
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default meta;
|
|
24
|
+
|
|
25
|
+
const Template: Story<Props> = args => {
|
|
26
|
+
return (
|
|
27
|
+
<I18nWrapper>
|
|
28
|
+
<LoginDrawer
|
|
29
|
+
{...args}
|
|
30
|
+
onClose={() => {}}
|
|
31
|
+
onLogin={console.log}
|
|
32
|
+
onLogout={() => {}}
|
|
33
|
+
tenant={tenant}
|
|
34
|
+
apiUrl="https://backend.memori.ai"
|
|
35
|
+
/>
|
|
36
|
+
</I18nWrapper>
|
|
37
|
+
);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// By passing using the Args format for exported stories, you can control the props for a component for reuse in a test
|
|
41
|
+
// https://storybook.js.org/docs/react/workflows/unit-testing
|
|
42
|
+
export const Default = Template.bind({});
|
|
43
|
+
Default.args = {
|
|
44
|
+
open: true,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const NeedsMissingData = Template.bind({});
|
|
48
|
+
NeedsMissingData.args = {
|
|
49
|
+
open: true,
|
|
50
|
+
__TEST__needMissingData: true,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const LoggedIn = Template.bind({});
|
|
54
|
+
LoggedIn.args = {
|
|
55
|
+
open: true,
|
|
56
|
+
user,
|
|
57
|
+
loginToken: 'token',
|
|
58
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { render } from '@testing-library/react';
|
|
2
|
+
import LoginDrawer from './LoginDrawer';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { tenant, expertReference, user } from '../../mocks/data';
|
|
5
|
+
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
// @ts-ignore
|
|
8
|
+
window.IntersectionObserver = jest.fn(() => ({
|
|
9
|
+
observe: jest.fn(),
|
|
10
|
+
unobserve: jest.fn(),
|
|
11
|
+
disconnect: jest.fn(),
|
|
12
|
+
takeRecords: jest.fn(),
|
|
13
|
+
}));
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('renders LoginDrawer closed unchanged', () => {
|
|
17
|
+
const { container } = render(
|
|
18
|
+
<LoginDrawer
|
|
19
|
+
onClose={jest.fn()}
|
|
20
|
+
apiUrl="https://backend.memori.ai"
|
|
21
|
+
tenant={tenant}
|
|
22
|
+
onLogin={jest.fn()}
|
|
23
|
+
onLogout={jest.fn()}
|
|
24
|
+
/>
|
|
25
|
+
);
|
|
26
|
+
expect(container).toMatchSnapshot();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('renders LoginDrawer open unchanged', () => {
|
|
30
|
+
const { container } = render(
|
|
31
|
+
<LoginDrawer
|
|
32
|
+
onClose={jest.fn()}
|
|
33
|
+
apiUrl="https://backend.memori.ai"
|
|
34
|
+
tenant={tenant}
|
|
35
|
+
onLogin={jest.fn()}
|
|
36
|
+
onLogout={jest.fn()}
|
|
37
|
+
open
|
|
38
|
+
/>
|
|
39
|
+
);
|
|
40
|
+
expect(container).toMatchSnapshot();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('renders LoginDrawer unlogged unchanged', () => {
|
|
44
|
+
const { container } = render(
|
|
45
|
+
<LoginDrawer
|
|
46
|
+
onClose={jest.fn()}
|
|
47
|
+
apiUrl="https://backend.memori.ai"
|
|
48
|
+
tenant={tenant}
|
|
49
|
+
onLogin={jest.fn()}
|
|
50
|
+
onLogout={jest.fn()}
|
|
51
|
+
open
|
|
52
|
+
/>
|
|
53
|
+
);
|
|
54
|
+
expect(container).toMatchSnapshot();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('renders LoginDrawer logged with missing data unchanged', () => {
|
|
58
|
+
const { container } = render(
|
|
59
|
+
<LoginDrawer
|
|
60
|
+
onClose={jest.fn()}
|
|
61
|
+
apiUrl="https://backend.memori.ai"
|
|
62
|
+
tenant={tenant}
|
|
63
|
+
onLogin={jest.fn()}
|
|
64
|
+
onLogout={jest.fn()}
|
|
65
|
+
open
|
|
66
|
+
__TEST__needMissingData
|
|
67
|
+
/>
|
|
68
|
+
);
|
|
69
|
+
expect(container).toMatchSnapshot();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('renders LoginDrawer logged in unchanged', () => {
|
|
73
|
+
const { container } = render(
|
|
74
|
+
<LoginDrawer
|
|
75
|
+
onClose={jest.fn()}
|
|
76
|
+
apiUrl="https://backend.memori.ai"
|
|
77
|
+
tenant={tenant}
|
|
78
|
+
onLogin={jest.fn()}
|
|
79
|
+
onLogout={jest.fn()}
|
|
80
|
+
open
|
|
81
|
+
user={user}
|
|
82
|
+
loginToken="token"
|
|
83
|
+
/>
|
|
84
|
+
);
|
|
85
|
+
expect(container).toMatchSnapshot();
|
|
86
|
+
});
|
|
@@ -0,0 +1,330 @@
|
|
|
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 Drawer from '../ui/Drawer';
|
|
5
|
+
import toast from 'react-hot-toast';
|
|
6
|
+
import { useTranslation } from 'react-i18next';
|
|
7
|
+
import cx from 'classnames';
|
|
8
|
+
import memoriApiClient from '@memori.ai/memori-api-client';
|
|
9
|
+
import { getErrori18nKey } from '../../helpers/error';
|
|
10
|
+
|
|
11
|
+
export const mailRegEx = /^\w+([.-]?[+]?\w+)*@\w+([.-]?\w+)*(\.\w{2,})+$/;
|
|
12
|
+
|
|
13
|
+
export interface Props {
|
|
14
|
+
open?: boolean;
|
|
15
|
+
onClose: () => void;
|
|
16
|
+
user?: User;
|
|
17
|
+
loginToken?: string;
|
|
18
|
+
onLogin: (user: User, token: string) => void;
|
|
19
|
+
onLogout: () => void;
|
|
20
|
+
tenant: Tenant;
|
|
21
|
+
apiUrl: string;
|
|
22
|
+
__TEST__needMissingData?: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const LoginDrawer = ({
|
|
26
|
+
open = false,
|
|
27
|
+
onClose,
|
|
28
|
+
onLogin,
|
|
29
|
+
onLogout,
|
|
30
|
+
user,
|
|
31
|
+
loginToken,
|
|
32
|
+
tenant,
|
|
33
|
+
apiUrl,
|
|
34
|
+
__TEST__needMissingData = false,
|
|
35
|
+
}: Props) => {
|
|
36
|
+
const { t, i18n } = useTranslation();
|
|
37
|
+
const lang = i18n.language === 'it' ? 'it' : 'en';
|
|
38
|
+
|
|
39
|
+
const client = memoriApiClient(apiUrl);
|
|
40
|
+
const { userLogin, updateUser } = client.backend;
|
|
41
|
+
|
|
42
|
+
const [loading, setLoading] = useState(false);
|
|
43
|
+
const [needsMissingData, setNeedsMissingData] = useState<{
|
|
44
|
+
token: string;
|
|
45
|
+
birthDate?: boolean;
|
|
46
|
+
tnCAndPPAccepted?: boolean;
|
|
47
|
+
}>(
|
|
48
|
+
__TEST__needMissingData
|
|
49
|
+
? {
|
|
50
|
+
token: 'token',
|
|
51
|
+
birthDate: true,
|
|
52
|
+
tnCAndPPAccepted: true,
|
|
53
|
+
}
|
|
54
|
+
: ({} as any)
|
|
55
|
+
);
|
|
56
|
+
const [error, setError] = useState<string | null>(null);
|
|
57
|
+
|
|
58
|
+
const [redirectTo, setRedirectTo] = useState<string | null>(null);
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
setRedirectTo(window.location.href);
|
|
61
|
+
}, []);
|
|
62
|
+
|
|
63
|
+
const isUserLoggedIn = user && loginToken;
|
|
64
|
+
|
|
65
|
+
const login = (e: React.FormEvent<HTMLFormElement>) => {
|
|
66
|
+
e.preventDefault();
|
|
67
|
+
const form = e.currentTarget as HTMLFormElement;
|
|
68
|
+
const userNameOrEmail = form.userNameOrEmail.value;
|
|
69
|
+
const password = form.password.value;
|
|
70
|
+
|
|
71
|
+
const isEmail = mailRegEx.test(userNameOrEmail);
|
|
72
|
+
const user: User = isEmail
|
|
73
|
+
? {
|
|
74
|
+
tenant: tenant?.id,
|
|
75
|
+
eMail: userNameOrEmail,
|
|
76
|
+
password: password,
|
|
77
|
+
}
|
|
78
|
+
: {
|
|
79
|
+
tenant: tenant?.id,
|
|
80
|
+
userName: userNameOrEmail,
|
|
81
|
+
password: password,
|
|
82
|
+
};
|
|
83
|
+
setLoading(true);
|
|
84
|
+
setError(null);
|
|
85
|
+
userLogin(user)
|
|
86
|
+
.then(data => {
|
|
87
|
+
if (data.resultCode !== 0) {
|
|
88
|
+
console.error(data);
|
|
89
|
+
toast.error(t(getErrori18nKey(data.resultCode), { ns: 'common' }));
|
|
90
|
+
setError(data.resultMessage);
|
|
91
|
+
} else if (data.user && data.token) {
|
|
92
|
+
onLogin(data.user as User, data.token);
|
|
93
|
+
|
|
94
|
+
if (!data.user?.tnCAndPPAccepted || !data.user?.birthDate) {
|
|
95
|
+
setNeedsMissingData({
|
|
96
|
+
token: data.token,
|
|
97
|
+
birthDate: !data.user?.birthDate,
|
|
98
|
+
tnCAndPPAccepted: !data.user?.tnCAndPPAccepted,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
})
|
|
103
|
+
.catch(err => {
|
|
104
|
+
console.error('[LOGIN]', err);
|
|
105
|
+
toast.error(err);
|
|
106
|
+
|
|
107
|
+
if (err.message) setError(err.message);
|
|
108
|
+
})
|
|
109
|
+
.finally(() => {
|
|
110
|
+
setLoading(false);
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const updateMissingData = async (e: React.FormEvent<HTMLFormElement>) => {
|
|
115
|
+
e.preventDefault();
|
|
116
|
+
const form = e.currentTarget as HTMLFormElement;
|
|
117
|
+
|
|
118
|
+
const birthDate = form.birthDate?.value;
|
|
119
|
+
const tnCAndPPAccepted = form.tnCAndPPAccepted?.checked;
|
|
120
|
+
const pAndCUAccepted = form.pAndCUAccepted?.checked;
|
|
121
|
+
|
|
122
|
+
if (!user?.userID || !needsMissingData?.token) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (!birthDate || !tnCAndPPAccepted) {
|
|
127
|
+
setError(t('missingData'));
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
let newUser: Partial<User> = {
|
|
132
|
+
userID: user.userID,
|
|
133
|
+
birthDate:
|
|
134
|
+
user?.birthDate || !needsMissingData.birthDate ? undefined : birthDate,
|
|
135
|
+
tnCAndPPAccepted: tnCAndPPAccepted || user?.tnCAndPPAccepted,
|
|
136
|
+
tnCAndPPAcceptanceDate: tnCAndPPAccepted
|
|
137
|
+
? new Date().toISOString()
|
|
138
|
+
: undefined,
|
|
139
|
+
pAndCUAccepted: pAndCUAccepted || user?.pAndCUAccepted,
|
|
140
|
+
pAndCUAcceptanceDate: pAndCUAccepted
|
|
141
|
+
? new Date().toISOString()
|
|
142
|
+
: undefined,
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const { user: patchedUser, ...resp } = await updateUser(
|
|
146
|
+
needsMissingData.token,
|
|
147
|
+
user.userID,
|
|
148
|
+
newUser
|
|
149
|
+
);
|
|
150
|
+
if (resp.resultCode !== 0) {
|
|
151
|
+
console.error(resp);
|
|
152
|
+
toast.error(t(getErrori18nKey(resp.resultCode), { ns: 'common' }));
|
|
153
|
+
setError(resp.resultMessage);
|
|
154
|
+
} else {
|
|
155
|
+
toast.success(t('success'));
|
|
156
|
+
onLogin(patchedUser || newUser, needsMissingData.token);
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
return (
|
|
161
|
+
<Drawer
|
|
162
|
+
open={open}
|
|
163
|
+
onClose={onClose}
|
|
164
|
+
className={cx('memori--login-drawer', {
|
|
165
|
+
'memori--login-drawer--logged': isUserLoggedIn,
|
|
166
|
+
})}
|
|
167
|
+
title={
|
|
168
|
+
<h2 className="memori--login-drawer--title">
|
|
169
|
+
{isUserLoggedIn
|
|
170
|
+
? t('login.loggedDrawerTitle', { name: user.userName })
|
|
171
|
+
: t('login.loginDrawerTitle')}
|
|
172
|
+
</h2>
|
|
173
|
+
}
|
|
174
|
+
>
|
|
175
|
+
{isUserLoggedIn ? (
|
|
176
|
+
<div className="memori--login-drawer--logged">
|
|
177
|
+
<Button
|
|
178
|
+
primary
|
|
179
|
+
onClick={() => {
|
|
180
|
+
onLogout();
|
|
181
|
+
}}
|
|
182
|
+
>
|
|
183
|
+
{t('login.logout')}
|
|
184
|
+
</Button>
|
|
185
|
+
</div>
|
|
186
|
+
) : needsMissingData?.token?.length ? (
|
|
187
|
+
<>
|
|
188
|
+
<h3>{t('login.missingData')}</h3>
|
|
189
|
+
<p>{t('login.missingDataHelper')}</p>
|
|
190
|
+
|
|
191
|
+
<form
|
|
192
|
+
className="memori--login-drawer--form"
|
|
193
|
+
onSubmit={updateMissingData}
|
|
194
|
+
>
|
|
195
|
+
{needsMissingData.birthDate && (
|
|
196
|
+
<>
|
|
197
|
+
<label htmlFor="#birthDate">
|
|
198
|
+
{t('login.birthDate')}
|
|
199
|
+
<input
|
|
200
|
+
id="birthDate"
|
|
201
|
+
name="birthDate"
|
|
202
|
+
type="date"
|
|
203
|
+
required
|
|
204
|
+
autoComplete="bday"
|
|
205
|
+
/>
|
|
206
|
+
</label>
|
|
207
|
+
<p>
|
|
208
|
+
<small>{t('login.birthDateHelper')}</small>
|
|
209
|
+
</p>
|
|
210
|
+
</>
|
|
211
|
+
)}
|
|
212
|
+
|
|
213
|
+
{needsMissingData?.tnCAndPPAccepted && (
|
|
214
|
+
<>
|
|
215
|
+
<label className="memori-checkbox">
|
|
216
|
+
<span className="memori-checkbox--input-wrapper">
|
|
217
|
+
<input
|
|
218
|
+
type="checkbox"
|
|
219
|
+
name="tnCAndPPAccepted"
|
|
220
|
+
className="memori-checkbox--input"
|
|
221
|
+
/>
|
|
222
|
+
<span className="memori-checkbox--inner" />
|
|
223
|
+
</span>
|
|
224
|
+
<span className="memori-checkbox--text">
|
|
225
|
+
{t('login.privacyLabel')}{' '}
|
|
226
|
+
<a
|
|
227
|
+
href={`https://memori.ai/${lang}/privacy_and_cookie`}
|
|
228
|
+
target="_blank"
|
|
229
|
+
rel="noopener noreferrer"
|
|
230
|
+
>
|
|
231
|
+
{t('login.privacyAndCookiePolicy')}
|
|
232
|
+
</a>{' '}
|
|
233
|
+
{t('login.and')}{' '}
|
|
234
|
+
<a
|
|
235
|
+
href={`https://memori.ai/${lang}/tos`}
|
|
236
|
+
target="_blank"
|
|
237
|
+
rel="noopener noreferrer"
|
|
238
|
+
>
|
|
239
|
+
{t('login.termsOfService')}
|
|
240
|
+
</a>
|
|
241
|
+
</span>
|
|
242
|
+
</label>
|
|
243
|
+
|
|
244
|
+
<label className="memori-checkbox">
|
|
245
|
+
<span className="memori-checkbox--input-wrapper">
|
|
246
|
+
<input
|
|
247
|
+
type="checkbox"
|
|
248
|
+
name="pAndCUAccepted"
|
|
249
|
+
defaultChecked={user?.pAndCUAccepted}
|
|
250
|
+
className="memori-checkbox--input"
|
|
251
|
+
/>
|
|
252
|
+
<span className="memori-checkbox--inner" />
|
|
253
|
+
</span>
|
|
254
|
+
<span className="memori-checkbox--text">
|
|
255
|
+
{t('login.pAndCUAccepted')}{' '}
|
|
256
|
+
<small>
|
|
257
|
+
<em>({t('login.optional')})</em>
|
|
258
|
+
</small>
|
|
259
|
+
</span>
|
|
260
|
+
</label>
|
|
261
|
+
<p>
|
|
262
|
+
<small>{t('login.goToAccountToChangeYourPreferences')}</small>
|
|
263
|
+
</p>
|
|
264
|
+
<p>
|
|
265
|
+
<small>{t('login.deepThoughtExplaination')}</small>
|
|
266
|
+
</p>
|
|
267
|
+
</>
|
|
268
|
+
)}
|
|
269
|
+
|
|
270
|
+
<Button htmlType="submit" primary loading={loading}>
|
|
271
|
+
{t('login.save')}
|
|
272
|
+
</Button>
|
|
273
|
+
</form>
|
|
274
|
+
</>
|
|
275
|
+
) : (
|
|
276
|
+
<>
|
|
277
|
+
<form className="memori--login-drawer--form" onSubmit={login}>
|
|
278
|
+
<label htmlFor="#userNameOrEmail">
|
|
279
|
+
{t('login.userNameOrEmail')}
|
|
280
|
+
<input
|
|
281
|
+
id="userNameOrEmail"
|
|
282
|
+
name="userNameOrEmail"
|
|
283
|
+
required
|
|
284
|
+
autoComplete="email"
|
|
285
|
+
placeholder="Username/email"
|
|
286
|
+
/>
|
|
287
|
+
</label>
|
|
288
|
+
|
|
289
|
+
<label htmlFor="#password">
|
|
290
|
+
Password
|
|
291
|
+
<input
|
|
292
|
+
id="password"
|
|
293
|
+
name="password"
|
|
294
|
+
type="password"
|
|
295
|
+
required
|
|
296
|
+
autoComplete="password"
|
|
297
|
+
placeholder="Password"
|
|
298
|
+
/>
|
|
299
|
+
</label>
|
|
300
|
+
|
|
301
|
+
<Button htmlType="submit" primary loading={loading}>
|
|
302
|
+
{t('login.login')}
|
|
303
|
+
</Button>
|
|
304
|
+
|
|
305
|
+
{!tenant?.disableRegistration && (
|
|
306
|
+
<p className="memori--login-drawer--signup">
|
|
307
|
+
{t('login.newUserSignUp')}{' '}
|
|
308
|
+
<a
|
|
309
|
+
href={`https://${
|
|
310
|
+
tenant.name || 'www.aisuru.com'
|
|
311
|
+
}/${lang}/auth?signup=1&redirectTo=${redirectTo}`}
|
|
312
|
+
>
|
|
313
|
+
{t('login.signUp')}
|
|
314
|
+
</a>
|
|
315
|
+
</p>
|
|
316
|
+
)}
|
|
317
|
+
</form>
|
|
318
|
+
|
|
319
|
+
{error && (
|
|
320
|
+
<p role="alert" className="memori--login-drawer--error">
|
|
321
|
+
{error}
|
|
322
|
+
</p>
|
|
323
|
+
)}
|
|
324
|
+
</>
|
|
325
|
+
)}
|
|
326
|
+
</Drawer>
|
|
327
|
+
);
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
export default LoginDrawer;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`renders LoginDrawer closed unchanged 1`] = `<div />`;
|
|
4
|
+
|
|
5
|
+
exports[`renders LoginDrawer logged in unchanged 1`] = `
|
|
6
|
+
<div>
|
|
7
|
+
<div
|
|
8
|
+
style="position: fixed; top: 1px; left: 1px; width: 1px; height: 0px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0px, 0px, 0px, 0px); white-space: nowrap; border-width: 0px; display: none;"
|
|
9
|
+
/>
|
|
10
|
+
</div>
|
|
11
|
+
`;
|
|
12
|
+
|
|
13
|
+
exports[`renders LoginDrawer logged with missing data unchanged 1`] = `
|
|
14
|
+
<div>
|
|
15
|
+
<div
|
|
16
|
+
style="position: fixed; top: 1px; left: 1px; width: 1px; height: 0px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0px, 0px, 0px, 0px); white-space: nowrap; border-width: 0px; display: none;"
|
|
17
|
+
/>
|
|
18
|
+
</div>
|
|
19
|
+
`;
|
|
20
|
+
|
|
21
|
+
exports[`renders LoginDrawer open unchanged 1`] = `
|
|
22
|
+
<div>
|
|
23
|
+
<div
|
|
24
|
+
style="position: fixed; top: 1px; left: 1px; width: 1px; height: 0px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0px, 0px, 0px, 0px); white-space: nowrap; border-width: 0px; display: none;"
|
|
25
|
+
/>
|
|
26
|
+
</div>
|
|
27
|
+
`;
|
|
28
|
+
|
|
29
|
+
exports[`renders LoginDrawer unlogged unchanged 1`] = `
|
|
30
|
+
<div>
|
|
31
|
+
<div
|
|
32
|
+
style="position: fixed; top: 1px; left: 1px; width: 1px; height: 0px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0px, 0px, 0px, 0px); white-space: nowrap; border-width: 0px; display: none;"
|
|
33
|
+
/>
|
|
34
|
+
</div>
|
|
35
|
+
`;
|
|
@@ -53,6 +53,7 @@ import AgeVerificationModal from '../AgeVerificationModal/AgeVerificationModal';
|
|
|
53
53
|
import SettingsDrawer from '../SettingsDrawer/SettingsDrawer';
|
|
54
54
|
import KnownFacts from '../KnownFacts/KnownFacts';
|
|
55
55
|
import ExpertsDrawer from '../ExpertsDrawer/ExpertsDrawer';
|
|
56
|
+
import LoginDrawer from '../LoginDrawer/LoginDrawer';
|
|
56
57
|
|
|
57
58
|
// Layout
|
|
58
59
|
import FullPageLayout from '../layouts/FullPage';
|
|
@@ -331,6 +332,7 @@ export interface Props {
|
|
|
331
332
|
showClear?: boolean;
|
|
332
333
|
showOnlyLastMessages?: boolean;
|
|
333
334
|
showTypingText?: boolean;
|
|
335
|
+
showLogin?: boolean;
|
|
334
336
|
preview?: boolean;
|
|
335
337
|
embed?: boolean;
|
|
336
338
|
height?: number | string;
|
|
@@ -349,6 +351,7 @@ export interface Props {
|
|
|
349
351
|
};
|
|
350
352
|
authToken?: string;
|
|
351
353
|
AZURE_COGNITIVE_SERVICES_TTS_KEY?: string;
|
|
354
|
+
defaultSpeakerActive?: boolean;
|
|
352
355
|
onStateChange?: (state?: DialogState) => void;
|
|
353
356
|
additionalInfo?: OpenSession['additionalInfo'] & { [key: string]: string };
|
|
354
357
|
customMediaRenderer?: ChatProps['customMediaRenderer'];
|
|
@@ -374,6 +377,7 @@ const MemoriWidget = ({
|
|
|
374
377
|
showSettings = true,
|
|
375
378
|
showTypingText = false,
|
|
376
379
|
showClear = false,
|
|
380
|
+
showLogin = true,
|
|
377
381
|
showOnlyLastMessages,
|
|
378
382
|
height = '100vh',
|
|
379
383
|
secret,
|
|
@@ -387,6 +391,7 @@ const MemoriWidget = ({
|
|
|
387
391
|
personification,
|
|
388
392
|
authToken,
|
|
389
393
|
AZURE_COGNITIVE_SERVICES_TTS_KEY,
|
|
394
|
+
defaultSpeakerActive = true,
|
|
390
395
|
onStateChange,
|
|
391
396
|
additionalInfo,
|
|
392
397
|
additionalSettings,
|
|
@@ -418,16 +423,22 @@ const MemoriWidget = ({
|
|
|
418
423
|
const [loginToken, setLoginToken] = useState<string | undefined>(
|
|
419
424
|
additionalInfo?.loginToken ?? authToken
|
|
420
425
|
);
|
|
421
|
-
const [user, setUser] = useState<User>({
|
|
426
|
+
const [user, setUser] = useState<User | undefined>({
|
|
422
427
|
avatarURL: typeof userAvatar === 'string' ? userAvatar : undefined,
|
|
423
428
|
} as User);
|
|
424
429
|
useEffect(() => {
|
|
425
|
-
if (loginToken) {
|
|
430
|
+
if (loginToken && !user?.userID) {
|
|
426
431
|
client.backend.getCurrentUser(loginToken).then(({ user, resultCode }) => {
|
|
427
|
-
if (user && resultCode === 0)
|
|
432
|
+
if (user && resultCode === 0) {
|
|
433
|
+
setUser(user);
|
|
434
|
+
setLocalConfig('loginToken', loginToken);
|
|
435
|
+
} else {
|
|
436
|
+
setLocalConfig('loginToken', undefined);
|
|
437
|
+
}
|
|
428
438
|
});
|
|
429
439
|
}
|
|
430
|
-
}, [loginToken]);
|
|
440
|
+
}, [loginToken, user?.userID]);
|
|
441
|
+
const [showLoginDrawer, setShowLoginDrawer] = useState(false);
|
|
431
442
|
|
|
432
443
|
const [clickedStart, setClickedStart] = useState(false);
|
|
433
444
|
const [gotErrorInOpening, setGotErrorInOpening] = useState(false);
|
|
@@ -467,7 +478,7 @@ const MemoriWidget = ({
|
|
|
467
478
|
const [showSettingsDrawer, setShowSettingsDrawer] = useState(false);
|
|
468
479
|
const [showKnownFactsDrawer, setShowKnownFactsDrawer] = useState(false);
|
|
469
480
|
const [showExpertsDrawer, setShowExpertsDrawer] = useState(false);
|
|
470
|
-
const [muteSpeaker, setMuteSpeaker] = useState(
|
|
481
|
+
const [muteSpeaker, setMuteSpeaker] = useState(!defaultSpeakerActive);
|
|
471
482
|
const [continuousSpeech, setContinuousSpeech] = useState(false);
|
|
472
483
|
const [continuousSpeechTimeout, setContinuousSpeechTimeout] = useState(2);
|
|
473
484
|
const [isPlayingAudio, setIsPlayingAudio] = useState(false);
|
|
@@ -504,14 +515,18 @@ const MemoriWidget = ({
|
|
|
504
515
|
defaultControlsPosition = 'bottom';
|
|
505
516
|
}
|
|
506
517
|
|
|
507
|
-
setMuteSpeaker(getLocalConfig('muteSpeaker',
|
|
508
|
-
speakerMuted = getLocalConfig('muteSpeaker',
|
|
518
|
+
setMuteSpeaker(getLocalConfig('muteSpeaker', !defaultSpeakerActive));
|
|
519
|
+
speakerMuted = getLocalConfig('muteSpeaker', !defaultSpeakerActive);
|
|
509
520
|
setContinuousSpeech(microphoneMode === 'CONTINUOUS');
|
|
510
521
|
setContinuousSpeechTimeout(getLocalConfig('continuousSpeechTimeout', 2));
|
|
511
522
|
setControlsPosition(
|
|
512
523
|
getLocalConfig('controlsPosition', defaultControlsPosition)
|
|
513
524
|
);
|
|
514
525
|
setHideEmissions(getLocalConfig('hideEmissions', false));
|
|
526
|
+
|
|
527
|
+
if (!additionalInfo?.loginToken && !authToken) {
|
|
528
|
+
setLoginToken(getLocalConfig<typeof loginToken>('loginToken', undefined));
|
|
529
|
+
}
|
|
515
530
|
}, []);
|
|
516
531
|
|
|
517
532
|
/**
|
|
@@ -2620,6 +2635,8 @@ const MemoriWidget = ({
|
|
|
2620
2635
|
showReload: selectedLayout === 'TOTEM',
|
|
2621
2636
|
showClear,
|
|
2622
2637
|
clearHistory: () => setHistory(h => h.slice(-1)),
|
|
2638
|
+
showLogin,
|
|
2639
|
+
setShowLoginDrawer,
|
|
2623
2640
|
loginToken,
|
|
2624
2641
|
user,
|
|
2625
2642
|
sessionID: sessionId,
|
|
@@ -2658,6 +2675,8 @@ const MemoriWidget = ({
|
|
|
2658
2675
|
onClickStart: onClickStart,
|
|
2659
2676
|
initializeTTS: initializeTTS,
|
|
2660
2677
|
isUserLoggedIn: !!loginToken,
|
|
2678
|
+
showLogin,
|
|
2679
|
+
setShowLoginDrawer,
|
|
2661
2680
|
user,
|
|
2662
2681
|
};
|
|
2663
2682
|
|
|
@@ -2944,6 +2963,33 @@ const MemoriWidget = ({
|
|
|
2944
2963
|
onClose={() => setShowExpertsDrawer(false)}
|
|
2945
2964
|
/>
|
|
2946
2965
|
)}
|
|
2966
|
+
|
|
2967
|
+
{showLoginDrawer && tenant?.id && (
|
|
2968
|
+
<LoginDrawer
|
|
2969
|
+
tenant={tenant}
|
|
2970
|
+
apiUrl={apiUrl}
|
|
2971
|
+
open={!!showLoginDrawer}
|
|
2972
|
+
user={user}
|
|
2973
|
+
loginToken={loginToken}
|
|
2974
|
+
onClose={() => setShowLoginDrawer(false)}
|
|
2975
|
+
onLogin={(user, token) => {
|
|
2976
|
+
setUser(user);
|
|
2977
|
+
setLoginToken(token);
|
|
2978
|
+
setShowLoginDrawer(false);
|
|
2979
|
+
setLocalConfig('loginToken', token);
|
|
2980
|
+
}}
|
|
2981
|
+
onLogout={() => {
|
|
2982
|
+
if (!loginToken) return;
|
|
2983
|
+
|
|
2984
|
+
client.backend.userLogout(loginToken).then(() => {
|
|
2985
|
+
setShowLoginDrawer(false);
|
|
2986
|
+
setUser(undefined);
|
|
2987
|
+
setLoginToken(undefined);
|
|
2988
|
+
setLocalConfig('loginToken', undefined);
|
|
2989
|
+
});
|
|
2990
|
+
}}
|
|
2991
|
+
/>
|
|
2992
|
+
)}
|
|
2947
2993
|
</div>
|
|
2948
2994
|
);
|
|
2949
2995
|
};
|
|
@@ -86,7 +86,7 @@ const Template: Story<Props> = args => (
|
|
|
86
86
|
{args.integrationConfig && (
|
|
87
87
|
<style dangerouslySetInnerHTML={{ __html: integrationStylesheet }} />
|
|
88
88
|
)}
|
|
89
|
-
<StartPanel {...args} />
|
|
89
|
+
<StartPanel {...args} setShowLoginDrawer={() => {}} />
|
|
90
90
|
</div>
|
|
91
91
|
</I18nWrapper>
|
|
92
92
|
);
|
|
@@ -228,6 +228,8 @@ WithDeepThoughtEnabledUnlogged.args = {
|
|
|
228
228
|
clickedStart: false,
|
|
229
229
|
onClickStart: () => {},
|
|
230
230
|
isUserLoggedIn: false,
|
|
231
|
+
showLogin: true,
|
|
232
|
+
setShowLoginDrawer: () => {},
|
|
231
233
|
};
|
|
232
234
|
|
|
233
235
|
export const WithDeepThoughtEnabledWithoutPermissionFlag = Template.bind({});
|