Skip to content

Commit 047e1c0

Browse files
committed
Merge branch 'fix/SPEK-167-disconnected-state' into screenshots/SPEK-155
2 parents 2dea091 + 54f69ba commit 047e1c0

File tree

4 files changed

+60
-9
lines changed

4 files changed

+60
-9
lines changed

src/renderer/features/contacts/BackendConfiguration/model/auth-model.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { combine, createEffect, createEvent, createStore, sample } from 'effector';
2-
import { once } from 'patronum';
2+
import { interval, once } from 'patronum';
33

44
import { type AccountId } from '@/shared/polkadotjs-schemas';
55
import { walletModel } from '@/entities/wallet';
@@ -187,7 +187,10 @@ sample({
187187
// Connection result tracking
188188
$connectionResult
189189
.on(signAndVerifyFx.done, () => ({ status: 'success' }) as ConnectionResult)
190-
.on([connectTriggered, signInClicked, backendConfigurationModel.events.urlCleared], () => ({ status: 'idle' }) as ConnectionResult);
190+
.on(
191+
[connectTriggered, signInClicked, backendConfigurationModel.events.urlCleared],
192+
() => ({ status: 'idle' }) as ConnectionResult,
193+
);
191194

192195
sample({
193196
clock: [requestChallengeFx.failData, signAndVerifyFx.failData],
@@ -256,13 +259,33 @@ sample({
256259
// On session check failure, clear auth state silently
257260
$authState.on(checkSessionFx.fail, () => null);
258261

262+
// Session expiry awareness: periodic health check every 5 minutes
263+
const $isSessionExpired = createStore(false);
264+
265+
const sessionHealthCheck = interval({
266+
timeout: 5 * 60 * 1000,
267+
start: signAndVerifyFx.done,
268+
stop: signOutClicked,
269+
});
270+
271+
sample({
272+
clock: sessionHealthCheck.tick,
273+
source: backendConfigurationModel.$backendUrl,
274+
filter: (url): url is string => url !== null,
275+
target: checkSessionFx,
276+
});
277+
278+
$isSessionExpired.on(checkSessionFx.fail, () => true);
279+
$isSessionExpired.on([signAndVerifyFx.done, signOutClicked, backendConfigurationModel.events.urlCleared], () => false);
280+
259281
export const authModel = {
260282
$authState,
261283
$authStep,
262284
$selectedAccountId,
263285
$error,
264286
$connectionResult,
265287
$isAuthenticated,
288+
$isSessionExpired,
266289
$extensionAccounts,
267290

268291
events: {

src/renderer/features/contacts/BackendConfiguration/ui/AuthStatus.tsx

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,30 @@
11
import { useUnit } from 'effector-react';
22

3+
import { useI18n } from '@/shared/i18n';
34
import { toAddress } from '@/shared/lib/utils';
4-
import { FootnoteText } from '@/shared/ui';
5+
import { FootnoteText, Icon } from '@/shared/ui';
56
import { Identicon } from '@/shared/ui-entities';
67
import { authModel } from '../model/auth-model';
78

89
export const AuthStatus = () => {
9-
const [isAuthenticated, authState] = useUnit([authModel.$isAuthenticated, authModel.$authState]);
10+
const { t } = useI18n();
11+
const [isAuthenticated, authState, isSessionExpired] = useUnit([
12+
authModel.$isAuthenticated,
13+
authModel.$authState,
14+
authModel.$isSessionExpired,
15+
]);
16+
17+
if (isSessionExpired) {
18+
return (
19+
<div className="flex items-center gap-x-1">
20+
<Icon name="warnCutout" size={14} className="text-text-warning" />
21+
<FootnoteText className="text-text-warning">{t('addressBook.auth.sessionExpired')}</FootnoteText>
22+
</div>
23+
);
24+
}
1025

1126
if (!isAuthenticated || !authState) {
12-
return null;
27+
return <FootnoteText className="text-text-tertiary">{t('addressBook.auth.disconnected')}</FootnoteText>;
1328
}
1429

1530
return (

src/renderer/features/contacts/BackendConfiguration/ui/BackendConnectionCard.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,33 @@ import { backendConfigurationModel } from '../model/backend-configuration-model'
99
import { AuthStatus } from './AuthStatus';
1010

1111
export const BackendConnectionCard = () => {
12-
const [hasBackend, backendUrl, isAuthenticated] = useUnit([
12+
const [hasBackend, backendUrl, isAuthenticated, isSessionExpired] = useUnit([
1313
backendConfigurationModel.$hasBackend,
1414
backendConfigurationModel.$backendUrl,
1515
authModel.$isAuthenticated,
16+
authModel.$isSessionExpired,
1617
]);
1718

1819
if (!hasBackend) return null;
1920

21+
const isDisconnected = !isAuthenticated || isSessionExpired;
22+
2023
return (
2124
<button
2225
type="button"
23-
className="flex h-full cursor-pointer items-center gap-x-1 rounded-md border border-filter-border bg-input-background px-2.5 hover:bg-hover"
26+
className={cnTw(
27+
'flex h-full cursor-pointer items-center gap-x-1 rounded-md border bg-input-background px-2.5 hover:bg-hover',
28+
isDisconnected ? 'border-text-warning' : 'border-filter-border',
29+
)}
2430
onClick={() => backendConfigurationModel.events.editStarted()}
2531
>
2632
<Icon
2733
name="globe"
2834
size={16}
29-
className={cnTw('shrink-0', isAuthenticated ? 'text-icon-positive' : 'text-icon-accent')}
35+
className={cnTw(
36+
'shrink-0',
37+
isSessionExpired ? 'text-text-warning' : isAuthenticated ? 'text-icon-positive' : 'text-icon-accent',
38+
)}
3039
/>
3140
<Tooltip enableHover delay={200}>
3241
<Tooltip.Trigger>

src/renderer/shared/i18n/locales/en.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,11 @@
9494
"noExtensionAccounts": "No extension wallet accounts available",
9595
"selectAccountLabel": "Select account",
9696
"selectAccountPlaceholder": "Choose an account",
97-
"signingMessage": "Waiting for signature..."
97+
"signOutButton": "Sign out",
98+
"signingMessage": "Waiting for signature...",
99+
"signInSuccess": "Successfully signed in",
100+
"sessionExpired": "Session expired",
101+
"disconnected": "Disconnected"
98102
},
99103
"backendConfiguration": {
100104
"addTitle": "Add Backend",

0 commit comments

Comments
 (0)