diff --git a/.vscode/settings.json b/.vscode/settings.json index 112501c360..57aa69f078 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -15,4 +15,6 @@ "typescript.suggest.paths": true, "typescript.suggest.enabled": true, "typescript.suggest.completeFunctionCalls": true, + }, + "typescript.tsdk": "node_modules/typescript/lib" } diff --git a/packages/app/src/systems/CRX/background/services/VaultService.ts b/packages/app/src/systems/CRX/background/services/VaultService.ts index e8530c5d24..959cf81e87 100644 --- a/packages/app/src/systems/CRX/background/services/VaultService.ts +++ b/packages/app/src/systems/CRX/background/services/VaultService.ts @@ -6,6 +6,7 @@ import { import type { DatabaseRestartEvent, RequestMessage } from '@fuel-wallet/types'; import { AUTO_LOCK_IN_MINUTES } from '~/config'; import { VaultServer } from '~/systems/Vault/services/VaultServer'; +import lockTimer from '../../utils/lockTimer'; import { clearSession, diff --git a/packages/app/src/systems/CRX/utils/secret.ts b/packages/app/src/systems/CRX/utils/secret.ts index c078ea2141..d058141d87 100644 --- a/packages/app/src/systems/CRX/utils/secret.ts +++ b/packages/app/src/systems/CRX/utils/secret.ts @@ -1,5 +1,6 @@ import dayjs from 'dayjs'; import { decrypt, encrypt } from 'fuels'; +import { AUTO_LOCK_IN_MINUTES } from '~/config'; const SALT_KEY = 'salt'; @@ -31,14 +32,21 @@ export async function resetTimer() { }); } +export async function saveLockTimeSetting(minutes: number) { + await chrome.storage.local.set({ userLockTime: minutes }); +} + export async function saveSecret(secret: string, autoLockInMinutes: number) { const salt = await createSalt(); try { + const { userLockTime } = await chrome.storage.local.get('userLockTime'); + const effectiveLockTime = userLockTime || autoLockInMinutes; + const encrypted = await encrypt(salt, secret); chrome.storage.session.set({ data: encrypted, - lockTime: autoLockInMinutes, - timer: dayjs().add(autoLockInMinutes, 'minute').valueOf(), + lockTime: effectiveLockTime, + timer: dayjs().add(effectiveLockTime, 'minute').valueOf(), }); } catch { clearSession(); diff --git a/packages/app/src/systems/Core/types.ts b/packages/app/src/systems/Core/types.ts index 01b0a3d971..5084b9dfa1 100644 --- a/packages/app/src/systems/Core/types.ts +++ b/packages/app/src/systems/Core/types.ts @@ -35,6 +35,7 @@ export const Pages = { settings: route('/settings'), settingsChangePassword: route('/settings/change-password'), settingsConnectedApps: route('/settings/connected-apps'), + settingsSetLockTimeout: route('/settings/set-lock'), // added send: route('/send'), sendConfirm: route('/send/confirm'), accounts: route('/accounts'), diff --git a/packages/app/src/systems/Settings/pages/LockTimeout/LockTimeout.stories.tsx b/packages/app/src/systems/Settings/pages/LockTimeout/LockTimeout.stories.tsx new file mode 100644 index 0000000000..ae1ae70e9b --- /dev/null +++ b/packages/app/src/systems/Settings/pages/LockTimeout/LockTimeout.stories.tsx @@ -0,0 +1,52 @@ +// import { LockTimeout } from "./LockTimeout"; +// import { Meta, Story } from '@storybook/react'; + +// export default { +// component: LockTimeout, +// title: 'Settings/Pages/4. LockTimeout', +// parameters: { +// viewport: { +// defaultViewport: 'chromeExtension', +// }, +// }, +// // loaders: [ +// // async () => { +// // // await AccountService.clearAccounts(); +// // // await AccountService.addAccount({ data: MOCK_ACCOUNTS[0] }); +// // return {}; +// // }, +// // ], +// } as Meta; + +// const Template: Story = (args) => ; + +import type { Meta, Story } from '@storybook/react'; +// LockTimer.stories.tsx +import React from 'react'; +import { LockTimeout } from './LockTimeout'; // Import the LockTimer component + +export default { + title: 'Components/LockTimer', // Storybook category and name + component: LockTimeout, // The component being showcased +} as Meta; + +const Template: Story = (args) => ; // Template for stories + +// Default state: Displays a list of lock times +export const Default = Template.bind({}); +Default.args = { + availableTimes: ['5 minutes', '10 minutes', '30 minutes', '1 hour'], +}; + +// Empty state: No lock times available +export const Empty = Template.bind({}); +Empty.args = { + availableTimes: [], +}; + +// Error state: Error loading times +export const ErrorState = Template.bind({}); +ErrorState.args = { + availableTimes: [], + error: 'Failed to load available lock times.', +}; diff --git a/packages/app/src/systems/Settings/pages/LockTimeout/LockTimeout.tsx b/packages/app/src/systems/Settings/pages/LockTimeout/LockTimeout.tsx new file mode 100644 index 0000000000..c514d0ab4a --- /dev/null +++ b/packages/app/src/systems/Settings/pages/LockTimeout/LockTimeout.tsx @@ -0,0 +1,107 @@ +import { Box, VStack } from '@fuel-ui/react'; +import dayjs from 'dayjs'; +import { useState } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { saveLockTimeSetting } from '~/systems/CRX/utils'; +import { Layout } from '~/systems/Core'; +import { Pages } from '~/systems/Core'; + +const availableTime = [ + '5 minutes', + '30 minutes', + '2 hours', + '6 hours', + '12 hours', + 'Never', +]; +export function LockTimeout() { + const navigate = useNavigate(); + const goBack = () => navigate(Pages.wallet()); + const [selectedTime, setSelectedTime] = useState( + availableTime[0] + ); + + const handleSelectTime = async (time: string) => { + setSelectedTime(time); + if (selectedTime === 'Never') { + await saveLockTimeSetting(Number.MAX_SAFE_INTEGER); + } + if (!selectedTime) return; + const timeValue = Number.parseInt(selectedTime); + + try { + await saveLockTimeSetting(timeValue); + + const { data } = await chrome.storage.session.get('data'); + if (data) { + await chrome.storage.session.set({ + timer: dayjs().add(timeValue, 'minute').valueOf(), + }); + } + } catch (err) { + console.error(err); + } + }; + + return ( + + + + + {availableTime.map((time) => { + return ( + handleSelectTime(time)} + > + {time} + {time === selectedTime && ( + ✔️ + )} + + ); + })} + + + + ); +} + +const cssObj: { [key: string]: React.CSSProperties } = { + container: { + fontFamily: 'Arial, sans-serif', + padding: '20px', + maxWidth: '400px', + margin: 'auto', + border: '1px solid #ddd', + borderRadius: '8px', + boxShadow: '0 2px 4px rgba(0,0,0,0.1)', + }, + title: { + textAlign: 'center', + marginBottom: '20px', + fontSize: '1.5rem', + color: '#333', + }, + list: { + listStyle: 'none', + padding: 0, + margin: 0, + }, + listItem: { + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + padding: '10px 10px', + margin: '5px 0', + borderRadius: '4px', + cursor: 'pointer', + transition: 'background-color 0.2s', + }, + checkMark: { + color: 'white', + fontWeight: 'bold', + borderRadius: '50%', + }, +}; diff --git a/packages/app/src/systems/Settings/pages/LockTimeout/index.tsx b/packages/app/src/systems/Settings/pages/LockTimeout/index.tsx new file mode 100644 index 0000000000..79df6c39de --- /dev/null +++ b/packages/app/src/systems/Settings/pages/LockTimeout/index.tsx @@ -0,0 +1 @@ +export * from './LockTimeout'; diff --git a/packages/app/src/systems/Settings/pages/index.ts b/packages/app/src/systems/Settings/pages/index.ts index 759891c07c..9cebe024d7 100644 --- a/packages/app/src/systems/Settings/pages/index.ts +++ b/packages/app/src/systems/Settings/pages/index.ts @@ -1,3 +1,4 @@ export { ViewSeedPhrase } from './ViewSeedPhrase'; export { ChangePassword } from './ChangePassword'; export { Connections } from './Connections'; +export { LockTimeout } from './LockTimeout'; diff --git a/packages/app/src/systems/Settings/routes.tsx b/packages/app/src/systems/Settings/routes.tsx index 3aebd9be41..5c7d009176 100644 --- a/packages/app/src/systems/Settings/routes.tsx +++ b/packages/app/src/systems/Settings/routes.tsx @@ -2,11 +2,13 @@ import { Route } from 'react-router-dom'; import { Pages } from '../Core/types'; -import { ChangePassword, Connections } from './pages'; +import { ChangePassword, Connections, LockTimeout } from './pages'; export const settingsRoutes = ( } path={Pages.settingsChangePassword()} /> } path={Pages.settingsConnectedApps()} /> + } path={Pages.settingsSetLockTimeout()} /> + {/* Test Page} /> */} ); diff --git a/packages/app/src/systems/Sidebar/constants/sidebarItems.ts b/packages/app/src/systems/Sidebar/constants/sidebarItems.ts index 2c4b1d3920..e886cbad82 100644 --- a/packages/app/src/systems/Sidebar/constants/sidebarItems.ts +++ b/packages/app/src/systems/Sidebar/constants/sidebarItems.ts @@ -74,6 +74,13 @@ export const sidebarItems = (hasErrors: boolean): Array => label: 'Change Password', path: Pages.settingsChangePassword(), }, + { + // added this object + key: 'set-lock-timeout', + icon: 'Clock', + label: 'Auto Lock', + path: Pages.settingsSetLockTimeout(), + }, { key: 'logout', icon: 'Logout',