Skip to content

Commit f9c686e

Browse files
committed
ui+home+connect: do not auto-create sessions
Sessions are no longer automatically created since the pairing phrase must be used within 10 minutes of creation. With these changes, the session is only created when the user clicks on the connect buttons.
1 parent fd03fc9 commit f9c686e

File tree

6 files changed

+73
-106
lines changed

6 files changed

+73
-106
lines changed

Diff for: app/src/components/common/AlertContainer.tsx

+4
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ const Styled = {
4848
color: ${props => props.theme.colors.offWhite};
4949
background-color: ${props => props.theme.colors.pink};
5050
}
51+
.Toastify__toast--warning {
52+
color: ${props => props.theme.colors.offWhite};
53+
background-color: ${props => props.theme.colors.gold};
54+
}
5155
`,
5256
};
5357

Diff for: app/src/components/common/Modal.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ const GlobalStyles = (theme: Theme) => `
1616
color: ${theme.colors.offWhite};
1717
background-color: ${theme.colors.blue};
1818
border-width: 0px;
19-
padding: 40px;
19+
padding: 32px 40px;
2020
}
2121
div.rc-dialog-title {
22-
font-size: ${theme.sizes.xxl};
23-
line-height: 42px;
22+
font-size: 32px;
23+
line-height: 40px;
2424
overflow: hidden;
2525
text-overflow: ellipsis;
2626
}

Diff for: app/src/components/connect/ConnectPage.tsx

+8-55
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
1-
import React, { useCallback, useState } from 'react';
1+
import React, { useEffect } from 'react';
22
import { observer } from 'mobx-react-lite';
33
import styled from '@emotion/styled';
4-
import nodeConnectSvg from 'assets/images/lightning-node-connect.svg';
54
import { usePrefixedTranslation } from 'hooks';
65
import { useStore } from 'store';
7-
import { BoltOutlined, Copy, DisplayLarge, QRCode } from 'components/base';
6+
import { DisplayLarge } from 'components/base';
87
import AddSession from './AddSession';
9-
import PurpleButton from './PurpleButton';
10-
import QRCodeModal from './QRCodeModal';
118
import SessionList from './SessionList';
129

1310
const Styled = {
@@ -17,65 +14,21 @@ const Styled = {
1714
Description: styled.div`
1815
margin-bottom: 32px;
1916
`,
20-
Actions: styled.div`
21-
> a,
22-
> button {
23-
margin-right: 16px;
24-
}
25-
`,
26-
Divider: styled.div`
27-
max-width: 640px;
28-
border: 1px solid #384770;
29-
margin: 32px 0;
30-
`,
3117
};
3218

3319
const ConnectPage: React.FC = () => {
3420
const { l } = usePrefixedTranslation('cmps.connect.ConnectPage');
35-
const [showQR, setShowQR] = useState(false);
3621
const { sessionStore } = useStore();
3722

38-
const toggleQRModal = useCallback(() => setShowQR(v => !v), []);
23+
useEffect(() => {
24+
sessionStore.fetchSessions();
25+
}, []);
3926

40-
const { Wrapper, Description, Actions, Divider } = Styled;
41-
return !sessionStore.hasMultiple ? (
42-
<Wrapper>
43-
<img src={nodeConnectSvg} alt={l('pageTitle')} />
44-
<DisplayLarge space={16}>{l('pageTitle')}</DisplayLarge>
45-
<Description>
46-
{l('description1')}
47-
<br />
48-
{l('description2')}
49-
</Description>
50-
<Actions>
51-
<a href={sessionStore.firstSessionTerminalUrl} target="_blank" rel="noreferrer">
52-
<PurpleButton>
53-
<BoltOutlined />
54-
{l('connectTerminalBtn')}
55-
</PurpleButton>
56-
</a>
57-
<PurpleButton secondary onClick={sessionStore.copyFirstPhrase}>
58-
<Copy />
59-
{l('copyPhraseBtn')}
60-
</PurpleButton>
61-
<PurpleButton secondary onClick={toggleQRModal}>
62-
<QRCode />
63-
{l('generateQrBtn')}
64-
</PurpleButton>
65-
<QRCodeModal
66-
url={sessionStore.firstSessionTerminalUrl}
67-
visible={showQR}
68-
onClose={toggleQRModal}
69-
/>
70-
</Actions>
71-
<Divider />
72-
<Description>{l('addlDesc')}</Description>
73-
<AddSession />
74-
</Wrapper>
75-
) : (
27+
const { Wrapper, Description } = Styled;
28+
return (
7629
<Wrapper>
7730
<DisplayLarge space={16}>{l('pageTitle')}</DisplayLarge>
78-
<Description>{l('description1')}</Description>
31+
<Description>{l('description')}</Description>
7932
<AddSession primary />
8033
<SessionList />
8134
</Wrapper>

Diff for: app/src/components/home/HomePage.tsx

+16-15
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ const Styled = {
3737
margin-right: 16px;
3838
}
3939
`,
40+
Column: styled(Column)`
41+
max-width: 480px;
42+
`,
4043
Image: styled.img`
4144
width: 100%;
4245
margin-bottom: 24px;
@@ -45,28 +48,30 @@ const Styled = {
4548

4649
const HomePage: React.FC = () => {
4750
const { l } = usePrefixedTranslation('cmps.home.HomePage');
48-
const [showQR, setShowQR] = useState(false);
51+
const [qrUrl, setQrUrl] = useState('');
4952
const [showVideo, setShowVideo] = useState(false);
5053
const { sessionStore } = useStore();
5154

52-
const toggleQRModal = useCallback(() => setShowQR(v => !v), []);
55+
const openQRModal = useCallback(
56+
async () => setQrUrl(await sessionStore.getNewSessionUrl()),
57+
[],
58+
);
59+
const closeQRModal = useCallback(() => setQrUrl(''), []);
5360
const toggleVideoModal = useCallback(() => setShowVideo(v => !v), []);
5461

55-
const { Wrapper, PurpleButton, YoutubeButton, Image } = Styled;
62+
const { Wrapper, PurpleButton, YoutubeButton, Column, Image } = Styled;
5663
return (
5764
<Wrapper>
5865
<Display semiBold space={16}>
5966
{l('pageTitle')}
6067
</Display>
6168
<Paragraph space={32}>{l('connectDesc')}</Paragraph>
6269
<Paragraph space={40}>
63-
<a href={sessionStore.firstSessionTerminalUrl} target="_blank" rel="noreferrer">
64-
<PurpleButton>
65-
<BoltOutlined />
66-
{l('connectTerminalBtn')}
67-
</PurpleButton>
68-
</a>
69-
<PurpleButton secondary onClick={toggleQRModal}>
70+
<PurpleButton onClick={sessionStore.connectToTerminalWeb}>
71+
<BoltOutlined />
72+
{l('connectTerminalBtn')}
73+
</PurpleButton>
74+
<PurpleButton secondary onClick={openQRModal}>
7075
<QRCode />
7176
{l('connectQrBtn')}
7277
</PurpleButton>
@@ -98,11 +103,7 @@ const HomePage: React.FC = () => {
98103
<Paragraph muted>{l('dashDesc')}</Paragraph>
99104
</Column>
100105
</Row>
101-
<QRCodeModal
102-
url={sessionStore.firstSessionTerminalUrl}
103-
visible={showQR}
104-
onClose={toggleQRModal}
105-
/>
106+
<QRCodeModal url={qrUrl} visible={!!qrUrl} onClose={closeQRModal} />
106107
<YoutubeModal
107108
videoId="5kH1ByxjkTM"
108109
visible={showVideo}

Diff for: app/src/i18n/locales/en-US.json

+2-8
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,7 @@
3838
"cmps.connect.AddSession.expiration": "Expiration",
3939
"cmps.connect.AddSession.expirationSuffix": "",
4040
"cmps.connect.ConnectPage.pageTitle": "Lightning Node Connect",
41-
"cmps.connect.ConnectPage.description1": "Lightning Node Connect enables you to connect to this node from the web.",
42-
"cmps.connect.ConnectPage.description2": "Copy the default pairing phrase below to paste it into your app to make your first connection.",
43-
"cmps.connect.ConnectPage.info": "You will need a unique session for each app you wish to connect.",
44-
"cmps.connect.ConnectPage.connectTerminalBtn": "Connect to Terminal",
45-
"cmps.connect.ConnectPage.copyPhraseBtn": "Copy Pairing Phrase",
46-
"cmps.connect.ConnectPage.generateQrBtn": "Connect with QR",
47-
"cmps.connect.ConnectPage.addlDesc": "If you’ve utilized your default pairing phrase, and want to create additional sessions.",
41+
"cmps.connect.ConnectPage.description": "Lightning Node Connect enables you to connect to this node from the web.",
4842
"cmps.connect.SessionRowHeader.label": "Label",
4943
"cmps.connect.SessionRowHeader.type": "Type",
5044
"cmps.connect.SessionRowHeader.state": "State",
@@ -57,7 +51,7 @@
5751
"cmps.connect.QRCodeModal.title": "LNC QR",
5852
"cmps.connect.QRCodeModal.desc": "Scan to connect to Terminal from your mobile phone.",
5953
"cmps.home.HomePage.pageTitle": "Home",
60-
"cmps.home.HomePage.connectDesc": "Connect your node to Terminal on the web via the link below. For mobile, generate a QR code to connect.",
54+
"cmps.home.HomePage.connectDesc": "Securely and privately connect your node to Terminal on the web via the link below. For mobile, generate a QR code to connect.",
6155
"cmps.home.HomePage.connectTerminalBtn": "Connect to Terminal",
6256
"cmps.home.HomePage.connectQrBtn": "Connect with QR",
6357
"cmps.home.HomePage.learnDesc": "The connection to your node occurs through the Lightning Node Connect protocol.",

Diff for: app/src/store/stores/sessionStore.ts

+40-25
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,13 @@ export default class SessionStore {
4444
return this.sortedSessions.filter(s => !s.isPaired);
4545
}
4646

47-
/** indicates if there are more than one sessions active */
48-
get hasMultiple() {
49-
return this.sortedSessions.length > 1;
50-
}
51-
52-
/** The URl to pair with Terminal Web for the first session */
53-
get firstSessionTerminalUrl() {
54-
return this.unpairedSessions.length > 0
55-
? this.unpairedSessions[0].terminalConnectUrl
56-
: '';
47+
/** The label to use for a new generated session */
48+
get nextSessionLabel() {
49+
const count = values(this.sessions).filter(s =>
50+
s.label.startsWith('Generated Session'),
51+
).length;
52+
const countText = count === 0 ? '' : ` (${count})`;
53+
return `Generated Session${countText}`;
5754
}
5855

5956
/**
@@ -88,19 +85,6 @@ export default class SessionStore {
8885

8986
this._store.log.info('updated sessionStore.sessions', toJS(this.sessions));
9087
});
91-
92-
// Ensures that there is at least one session created
93-
if (this.unpairedSessions.length === 0) {
94-
const count = values(this.sessions).filter(s =>
95-
s.label.startsWith('Default Session'),
96-
).length;
97-
const countText = count === 0 ? '' : `(${count})`;
98-
await this.addSession(
99-
`Default Session ${countText}`,
100-
LIT.SessionType.TYPE_MACAROON_ADMIN,
101-
MAX_DATE,
102-
);
103-
}
10488
} catch (error: any) {
10589
this._store.appView.handleError(error, 'Unable to fetch sessions');
10690
}
@@ -138,15 +122,46 @@ export default class SessionStore {
138122
// fetch all sessions to update the store's state
139123
await this.fetchSessions();
140124

141-
if (session && copy) {
142-
this.copyPhrase(session.label, session.pairingSecretMnemonic);
125+
if (session) {
126+
if (copy) this.copyPhrase(session.label, session.pairingSecretMnemonic);
127+
const msg =
128+
'Please connect immediately. The pairing phrase will expire in 10 minutes.';
129+
this._store.appView.notify(msg, 'Session Created', 'warning');
143130
return this.sessions.get(hex(session.localPublicKey));
144131
}
145132
} catch (error: any) {
146133
this._store.appView.handleError(error, 'Unable to add session');
147134
}
148135
}
149136

137+
/**
138+
* Creates a new session if necessary and returns the Terminal Web url
139+
*/
140+
async getNewSessionUrl() {
141+
let session = this.unpairedSessions.length > 0 ? this.unpairedSessions[0] : undefined;
142+
if (!session) {
143+
session = await this.addSession(
144+
this.nextSessionLabel,
145+
LIT.SessionType.TYPE_MACAROON_ADMIN,
146+
MAX_DATE,
147+
);
148+
}
149+
return session ? session.terminalConnectUrl : '';
150+
}
151+
152+
/**
153+
* Opens the Terminal Web connect page in a new tab
154+
*/
155+
async connectToTerminalWeb() {
156+
// open the window first, then set the url when the async function returns. This is done
157+
// in this order because popup blockers will prevent the page from opening if the open()
158+
// function is not in the immediate callstack of a user initiated action, such as a
159+
// button click. If open() was called after the `await`, it would be blocked
160+
const tab = window.open();
161+
const url = await this.getNewSessionUrl();
162+
if (tab) tab.location.replace(url);
163+
}
164+
150165
/**
151166
* Revokes a session
152167
* @param session the Terminal Connect session object

0 commit comments

Comments
 (0)