Skip to content

Commit

Permalink
Add a signUp page
Browse files Browse the repository at this point in the history
  • Loading branch information
mrruby committed Mar 18, 2024
1 parent 64ce4fe commit 2710684
Show file tree
Hide file tree
Showing 16 changed files with 187 additions and 108 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ build
.env
.env.*
!.env.example
.vscode

holo-key-manager-js-client/lib

Expand Down
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ build
.env.*
!.env.example
package.json
.vscode

holo-key-manager-js-client/lib

Expand Down
17 changes: 17 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"prettier.requireConfig": true,
"prettier.documentSelectors": ["**/*.svelte"],
"[svelte]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
},
"editor.formatOnSave": true,
}
83 changes: 53 additions & 30 deletions holo-key-manager-extension/scripts/background.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,38 @@
import { GENERIC_ERROR, NEEDS_SETUP, SENDER_EXTENSION, SIGN_UP, SUCCESS } from '@sharedConst';
import { isSetupComplete } from '@sharedServices';
import {
GENERIC_ERROR,
NEEDS_SETUP,
NO_KEY_FOR_HAPP,
SENDER_EXTENSION,
SIGN_IN,
SIGN_UP,
SUCCESS
} from '@sharedConst';
import { isAppSignUpComplete, isSetupComplete } from '@sharedServices';
import { type ActionPayload, type Message, MessageWithIdSchema } from '@sharedTypes';

let windowId: number | undefined;

type SendResponse = (response?: Message) => void;
type SendResponseWithSender = (response: ActionPayload) => void;

const handleError = (error: string, sendResponse: SendResponseWithSender) => {
const handleError = (sendResponse: SendResponseWithSender) => {
windowId = undefined;
sendResponse({ action: GENERIC_ERROR });
};

const updateWindowFocus = (sendResponse: SendResponseWithSender) => {
chrome.windows.update(windowId as number, { focused: true }, () => {
if (chrome.runtime.lastError) {
handleError(sendResponse);
} else {
sendResponse({ action: SUCCESS });
}
});
};

const createAndFocusWindow = async (sendResponse: SendResponseWithSender) => {
if (typeof windowId === 'number') {
chrome.windows.update(windowId, { focused: true }, () => {
if (chrome.runtime.lastError) {
handleError('Error focusing window: ' + chrome.runtime.lastError.message, sendResponse);
} else {
sendResponse({ action: SUCCESS });
}
});
updateWindowFocus(sendResponse);
return true;
}
return false;
Expand All @@ -29,7 +41,7 @@ const createAndFocusWindow = async (sendResponse: SendResponseWithSender) => {
const createWindow = () => {
chrome.windows.create(
{
url: 'sign.html',
url: 'sign-up-key.html',
type: 'popup',
height: 500,
width: 375,
Expand All @@ -47,35 +59,46 @@ const createWindow = () => {
};

const handleAction = async (
actionType: typeof SUCCESS | typeof NEEDS_SETUP,
actionType: typeof SUCCESS | typeof NEEDS_SETUP | typeof NO_KEY_FOR_HAPP,
sendResponse: SendResponseWithSender
) => {
if (await createAndFocusWindow(sendResponse)) return;
createWindow();
if (!(await createAndFocusWindow(sendResponse))) {
createWindow();
}
sendResponse({ action: actionType });
};

chrome.runtime.onMessage.addListener((message: Message, sender, sendResponse: SendResponse) => {
(async () => {
const sendResponseWithSender = (response: ActionPayload) =>
sendResponse({ ...response, sender: SENDER_EXTENSION });
const processMessage = async (message: Message, sendResponse: SendResponse) => {
const sendResponseWithSender = (response: ActionPayload) =>
sendResponse({ ...response, sender: SENDER_EXTENSION });

const parsedMessage = MessageWithIdSchema.safeParse(message);
if (!parsedMessage.success) return;
if (parsedMessage.data.action !== SIGN_UP) return;
const parsedMessage = MessageWithIdSchema.safeParse(message);
if (!parsedMessage.success) return;

try {
const setupComplete = await isSetupComplete();
const actionType = setupComplete ? SUCCESS : NEEDS_SETUP;
if (!setupComplete) {
return handleAction(NEEDS_SETUP, sendResponseWithSender);
}

try {
handleAction(actionType, sendResponseWithSender);
} catch (error) {
handleError(
`Error processing sign in: ${error instanceof Error ? error.message : String(error)}`,
sendResponseWithSender
);
if (parsedMessage.data.action === SIGN_UP) {
return handleAction(SUCCESS, sendResponseWithSender);
}
})();

const signUpIncomplete =
parsedMessage.data.action === SIGN_IN &&
!(await isAppSignUpComplete(parsedMessage.data.payload.happId));
if (signUpIncomplete) {
return sendResponseWithSender({ action: NO_KEY_FOR_HAPP });
}

return handleAction(SUCCESS, sendResponseWithSender);
} catch (error) {
handleError(sendResponseWithSender);
}
};

chrome.runtime.onMessage.addListener((message: Message, sender, sendResponse: SendResponse) => {
processMessage(message, sendResponse);
return true;
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
import { AppParagraph, Button } from '$components';
import { dismissWindow } from '$lib/helpers';
function redirectToSetup() {
window.open('setup-pass/start.html', '_blank');
}
export let outerWindow = false;
export let mainAction: () => void;
export let mainActionLabel: string;
export let title: string;
export let subTitle: string;
</script>

<div class="m-8">
Expand All @@ -21,13 +21,10 @@

<div class="flex flex-col items-center justify-center">
<img src="/img/setup.svg" alt="Setup" class="max-w-[48px]" />
<h1 class="mt-4 text-2xl font-bold">Setup Required</h1>
<AppParagraph
extraProps="my-4 max-w-xs text-center"
text="You are yet to setup Holo Key Manager. Click “start setup” to begin."
/>
<h1 class="mt-4 text-2xl font-bold">{title}</h1>
<AppParagraph extraProps="my-4 max-w-xs text-center" text={subTitle} />
</div>

<Button label="Start setup" onClick={redirectToSetup} extraBottomMargin />
<Button label={mainActionLabel} onClick={mainAction} extraBottomMargin />
<Button label="Cancel" onClick={dismissWindow} color="secondary" />
</div>
2 changes: 1 addition & 1 deletion holo-key-manager-extension/src/lib/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export { default as ActionPage } from './ActionPage.svelte';
export { default as AppContainer } from './AppContainer.svelte';
export { default as AppParagraph } from './AppParagraph.svelte';
export { default as Button } from './Button.svelte';
export { default as Init } from './Init.svelte';
export { default as InputPassword } from './InputPassword.svelte';
export { default as Login } from './Login.svelte';
export { default as Title } from './Title.svelte';
24 changes: 16 additions & 8 deletions holo-key-manager-extension/src/routes/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
<script lang="ts">
import { Init, Login } from '$components';
import { ActionPage, Login } from '$components';
import { dismissWindow } from '$helpers';
import { sessionStorageQueries } from '$queries';
const { sessionQuery, setupDeviceKeyQuery } = sessionStorageQueries();
$: isLoading = $sessionQuery.isFetching || $setupDeviceKeyQuery.isFetching;
$: hasSessionData = $sessionQuery.data;
$: hasSetupData = $setupDeviceKeyQuery.data;
function redirectToChangePassword() {
window.open('change-password.html', '_blank');
}
const openInNewTab = (url: string) => () => window.open(url, '_blank');
const redirectToChangePassword = openInNewTab('change-password.html');
const redirectToSetup = openInNewTab('setup-pass/start.html');
</script>

{#if $sessionQuery.isFetching || $setupDeviceKeyQuery.isFetching}
{#if isLoading}
<span>Loading</span>
{:else if $sessionQuery.data}
{:else if hasSessionData}
<div class="m-8">
<div class="mb-4 flex items-center justify-between">
<img src="/img/holo_logo.svg" alt="Holo Key Manager Logo" />
Expand All @@ -25,8 +28,13 @@
Change Password
</button>
</div>
{:else if $setupDeviceKeyQuery.data}
{:else if hasSetupData}
<Login />
{:else}
<Init />
<ActionPage
mainAction={redirectToSetup}
mainActionLabel="Setup"
title="Setup Required"
subTitle="You are yet to setup Holo Key Manager. Click “start setup” to begin."
/>
{/if}
37 changes: 37 additions & 0 deletions holo-key-manager-extension/src/routes/sign-up-key/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<script lang="ts">
import { ActionPage, Login } from '$components';
import { sessionStorageQueries } from '$queries';
const { sessionQuery, setupDeviceKeyQuery } = sessionStorageQueries();
$: isLoading = $sessionQuery.isFetching || $setupDeviceKeyQuery.isFetching;
$: hasSessionData = $sessionQuery.data;
$: hasSetupData = $setupDeviceKeyQuery.data;
</script>

<svelte:head>
<title>Holo Key Manager</title>
</svelte:head>

<div class="mx-auto flex h-screen w-full max-w-[375px] flex-col items-center justify-center py-8">
{#if isLoading}
<span>Loading</span>
{:else if hasSessionData}
<ActionPage
outerWindow={true}
mainAction={() => {}}
mainActionLabel="Connect"
title="Holo Key Manager"
subTitle="Haxe would like to connect to Holo Key Manager"
/>
{:else if hasSetupData}
<Login outerWindow={true} />
{:else}
<ActionPage
outerWindow={true}
mainAction={() => window.open('setup-pass/start.html', '_blank')}
mainActionLabel="Setup"
title="Setup Required"
subTitle="You are yet to setup Holo Key Manager. Click “start setup” to begin."
/>
{/if}
</div>
28 changes: 0 additions & 28 deletions holo-key-manager-extension/src/routes/sign/+page.svelte

This file was deleted.

9 changes: 8 additions & 1 deletion holo-key-manager-js-client/src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { HOLO_KEY_MANAGER_EXTENSION_MARKER_ID, SENDER_WEBAPP } from '@sharedCons
import { createMessageWithId } from '@sharedServices';
import { type Message, type MessageWithId, MessageWithIdSchema } from '@sharedTypes';

let timeoutId: number | null = null;

const isWindowDefined = () => typeof window !== 'undefined';

export const sendMessage = (message: Message): Promise<MessageWithId> =>
Expand All @@ -11,6 +13,11 @@ export const sendMessage = (message: Message): Promise<MessageWithId> =>
return;
}

if (timeoutId) {
clearTimeout(timeoutId);
timeoutId = null;
}

const messageWithId = createMessageWithId(message);

const removeListener = () => window.removeEventListener('message', responseHandler);
Expand All @@ -30,7 +37,7 @@ export const sendMessage = (message: Message): Promise<MessageWithId> =>
window.postMessage(messageWithId, '*');
window.addEventListener('message', responseHandler);

setTimeout(() => {
timeoutId = setTimeout(() => {
removeListener();
reject(new Error('Response timeout'));
}, 30000);
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@
"buildExtension": "cd holo-key-manager-extension && pnpm build && cd ..",
"buildExtensionDev": "cd holo-key-manager-extension && pnpm buildDev && cd ..",
"buildClient": "cd holo-key-manager-js-client && pnpm buildPack && cd ..",
"buildDev": "concurrently \"pnpm buildExtensionDev\" \"pnpm buildClient\"",
"buildDev": "pnpm lintAndFormat && concurrently \"pnpm buildExtensionDev\" \"pnpm buildClient\"",
"lint": "prettier --check '**/*.{js,ts,svelte,json}' && eslint --fix '**/*.{js,ts,svelte}'",
"format": "prettier --write '**/*.{js,ts,svelte,json}'",
"check": "cd holo-key-manager-extension && pnpm check",
"lintAndFormat": "concurrently \"pnpm lint && pnpm format\" \"pnpm check\"",
"prepare": "husky install"
},
"devDependencies": {
Expand Down
1 change: 0 additions & 1 deletion shared/const/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,4 @@ export const SIGN_IN = 'SignIn';
export const NO_KEY_FOR_HAPP = 'NoKeyForHapp';
export const GENERIC_ERROR = 'GenericError';
export const SUCCESS = 'Success';
export const SUCCESS_WITH_PAYLOAD = 'SuccessWithPayload';
export const NEEDS_SETUP = 'NeedsSetup';
1 change: 1 addition & 0 deletions shared/const/secure-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export const LOCAL = 'local';
export const SESSION_DATA = 'sessionData';
export const PASSWORD = 'password';
export const DEVICE_KEY = 'deviceKey';
export const APPS_LIST = 'appsList';
13 changes: 12 additions & 1 deletion shared/services/storage.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { DEVICE_KEY, LOCAL } from '../const';
import { APPS_LIST, DEVICE_KEY, LOCAL } from '../const';
import { isChromeStorageSafe } from '../helpers';
import {
AppsListSchema,
type AreaName,
type ChangesType,
EncryptedDeviceKeySchema,
Expand Down Expand Up @@ -54,3 +55,13 @@ export const isSetupComplete = async () => {
const parsedData = EncryptedDeviceKeySchema.safeParse(data);
return parsedData.success;
};

export const isAppSignUpComplete = async (happId: string) => {
const data = await storageService.getWithoutCallback({
key: APPS_LIST,
area: LOCAL
});

const parsedData = AppsListSchema.safeParse(data);
return parsedData.success && parsedData.data.some((app) => app.happId === happId);
};
Loading

0 comments on commit 2710684

Please sign in to comment.