Skip to content

Commit

Permalink
Fix modals to use native form submit
Browse files Browse the repository at this point in the history
  • Loading branch information
therealparmesh committed May 28, 2024
1 parent ec836ba commit f8c5211
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 84 deletions.
60 changes: 29 additions & 31 deletions src/components/CreatePinModal/CreatePinModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import { useIntl } from '@cookbook/solid-intl';
import { Component, createEffect, createSignal } from 'solid-js';
import Modal from '../Modal/Modal';

import { login as tLogin, pin as tPin, actions as tActions } from '../../translations';
import {
login as tLogin,
pin as tPin,
actions as tActions,
} from '../../translations';

import styles from './CreatePinModal.module.scss';
import { hookForDev } from '../../lib/devTools';
Expand All @@ -12,13 +16,12 @@ import ButtonSecondary from '../Buttons/ButtonSecondary';
import { encryptWithPin, setCurrentPin } from '../../lib/PrimalNostr';

const CreatePinModal: Component<{
id?: string,
open?: boolean,
valueToEncrypt?: string,
onPinApplied?: (encryptedValue: string) => void,
onAbort?: () => void,
id?: string;
open?: boolean;
valueToEncrypt?: string;
onPinApplied?: (encryptedValue: string) => void;
onAbort?: () => void;
}> = (props) => {

const intl = useIntl();

let pinInput: HTMLInputElement | undefined;
Expand All @@ -32,7 +35,7 @@ const CreatePinModal: Component<{
return enc;
};

const onSetPin = async() => {
const onSetPin = async () => {
if (!isValidPin || !isValidRePin()) return;

// Encrypt private key
Expand All @@ -57,29 +60,27 @@ const CreatePinModal: Component<{

const isValidPin = () => {
return pin().length > 3;
}
};

const isValidRePin = () => {
return rePin() === pin();
};

const onKeyUp = (e: KeyboardEvent) => {
if (e.code === 'Enter' && isValidPin() && isValidRePin()) {
const onSubmit = (e: Event) => {
e.preventDefault();

if (isValidPin() && isValidRePin()) {
onSetPin();
}
};



return (
<Modal open={props.open} onClose={props.onAbort}>
<div id={props.id} class={styles.modal}>
<form id={props.id} class={styles.modal} onSubmit={onSubmit}>
<button class={styles.xClose} onClick={props.onAbort}>
<div class={styles.iconClose}></div>
</button>
<div class={styles.title}>
{intl.formatMessage(tPin.title)}
</div>
<div class={styles.title}>{intl.formatMessage(tPin.title)}</div>
<div class={styles.description}>
{intl.formatMessage(tPin.description)}
</div>
Expand All @@ -88,41 +89,38 @@ const CreatePinModal: Component<{
type="password"
ref={pinInput}
value={pin()}
onKeyUp={onKeyUp}
onChange={(val: string) => setPin(val)}
validationState={pin().length === 0 || isValidPin() ? 'valid' : 'invalid'}
validationState={
pin().length === 0 || isValidPin() ? 'valid' : 'invalid'
}
errorMessage={intl.formatMessage(tPin.invalidPin)}
/>

<div class={styles.description}>
{intl.formatMessage(tPin.reEnter)}
</div>
<div class={styles.description}>{intl.formatMessage(tPin.reEnter)}</div>
<TextInput
type="password"
value={rePin()}
onKeyUp={onKeyUp}
onChange={(val: string) => setRePin(val)}
validationState={rePin().length === 0 || isValidRePin() ? 'valid' : 'invalid'}
validationState={
rePin().length === 0 || isValidRePin() ? 'valid' : 'invalid'
}
errorMessage={intl.formatMessage(tPin.invalidRePin)}
/>

<div class={styles.actions}>
<ButtonPrimary
onClick={onSetPin}
type="submit"
disabled={!isValidPin() || !isValidRePin()}
>
{intl.formatMessage(tActions.createPin)}
</ButtonPrimary>
<ButtonSecondary
onClick={onOptout}
light={true}
>
<ButtonSecondary onClick={onOptout} light={true}>
{intl.formatMessage(tActions.optoutPin)}
</ButtonSecondary>
</div>
</div>
</form>
</Modal>
);
}
};

export default hookForDev(CreatePinModal);
57 changes: 24 additions & 33 deletions src/components/EnterPinModal/EnterPinModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { useToastContext } from '../Toaster/Toaster';

import { nip19 } from 'nostr-tools';


import { pin as tPin, actions as tActions } from '../../translations';

import styles from './EnterPinModal.module.scss';
Expand All @@ -18,14 +17,13 @@ import ButtonSecondary from '../Buttons/ButtonSecondary';
import { useAccountContext } from '../../contexts/AccountContext';

const EnterPinModal: Component<{
id?: string,
open?: boolean,
valueToDecrypt?: string,
onSuccess?: (decryptedValue: string) => void,
onAbort?: () => void,
onForgot?: () => void,
id?: string;
open?: boolean;
valueToDecrypt?: string;
onSuccess?: (decryptedValue: string) => void;
onAbort?: () => void;
onForgot?: () => void;
}> = (props) => {

const intl = useIntl();
const toast = useToastContext();
const account = useAccountContext();
Expand All @@ -40,7 +38,7 @@ const EnterPinModal: Component<{
return dec;
};

const onConfirm = async() => {
const onConfirm = async () => {
if (!isValidPin) return;

// Decrypt private key
Expand All @@ -50,19 +48,18 @@ const EnterPinModal: Component<{
const decoded = nip19.decode(enc);

if (decoded.type !== 'nsec' || !decoded.data) {
throw('invalid-nsec-decoded');
throw 'invalid-nsec-decoded';
}

// Save PIN for the session
setCurrentPin(pin());

// Execute callback
props.onSuccess && props.onSuccess(enc);
} catch(e) {
} catch (e) {
logError('Failed to decode nsec: ', e);
toast?.sendWarning('PIN is incorrect');
}

};

createEffect(() => {
Expand All @@ -73,54 +70,48 @@ const EnterPinModal: Component<{

const isValidPin = () => {
return pin().length > 3;
}
};

const onKeyUp = (e: KeyboardEvent) => {
if (e.code === 'Enter' && isValidPin()) {
const onSubmit = (e: Event) => {
e.preventDefault();

if (isValidPin()) {
onConfirm();
}
};

return (
<Modal open={props.open} opaqueBackdrop={true}>
<div id={props.id} class={styles.modal}>
<form id={props.id} class={styles.modal} onSubmit={onSubmit}>
<button class={styles.xClose} onClick={props.onAbort}>
<div class={styles.iconClose}></div>
</button>
<div class={styles.title}>
{intl.formatMessage(tPin.enterTitle)}
</div>
<div class={styles.description}>
{intl.formatMessage(tPin.enter)}
</div>
<div class={styles.title}>{intl.formatMessage(tPin.enterTitle)}</div>
<div class={styles.description}>{intl.formatMessage(tPin.enter)}</div>
<div class={styles.inputs}>
<TextInput
type="password"
ref={pinInput}
value={pin()}
onKeyUp={onKeyUp}
onChange={(val: string) => setPin(val)}
validationState={pin().length === 0 || isValidPin() ? 'valid' : 'invalid'}
validationState={
pin().length === 0 || isValidPin() ? 'valid' : 'invalid'
}
errorMessage={intl.formatMessage(tPin.invalidRePin)}
/>
</div>
<div class={styles.actions}>
<ButtonPrimary
onClick={onConfirm}
disabled={!isValidPin()}
>
<ButtonPrimary type="submit" disabled={!isValidPin()}>
{intl.formatMessage(tActions.login)}
</ButtonPrimary>

<ButtonSecondary
onClick={props.onForgot}
>
<ButtonSecondary onClick={props.onForgot}>
{intl.formatMessage(tActions.forgotPin)}
</ButtonSecondary>
</div>
</div>
</form>
</Modal>
);
}
};

export default hookForDev(EnterPinModal);
42 changes: 22 additions & 20 deletions src/components/LoginModal/LoginModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,14 @@ import { nip19 } from 'nostr-tools';
import { storeSec } from '../../lib/localStore';

const LoginModal: Component<{
id?: string,
open?: boolean,
onAbort?: () => void,
id?: string;
open?: boolean;
onAbort?: () => void;
}> = (props) => {

const intl = useIntl();
const account = useAccountContext();

const [step, setStep] = createSignal<'login' | 'pin' | 'none'>('login')
const [step, setStep] = createSignal<'login' | 'pin' | 'none'>('login');
const [enteredKey, setEnteredKey] = createSignal('');

let loginInput: HTMLInputElement | undefined;
Expand All @@ -39,13 +38,13 @@ const LoginModal: Component<{
const onStoreSec = (sec: string | undefined) => {
storeSec(sec);
onAbort();
}
};

const onAbort = () => {
setStep(() => 'login');
setEnteredKey('');
props.onAbort && props.onAbort();
}
};

const isValidNsec: () => boolean = () => {
const key = enteredKey();
Expand All @@ -58,8 +57,8 @@ const LoginModal: Component<{
try {
const decoded = nip19.decode(key);

return decoded.type === 'nsec' && decoded.data;
} catch(e) {
return Boolean(decoded.type === 'nsec' && decoded.data);
} catch (e) {
return false;
}
}
Expand All @@ -73,8 +72,10 @@ const LoginModal: Component<{
}
});

const onKeyUp = (e: KeyboardEvent) => {
if (e.code === 'Enter' && isValidNsec()) {
const onSubmit = (e: Event) => {
e.preventDefault();

if (isValidNsec()) {
onLogin();
}
};
Expand All @@ -83,13 +84,11 @@ const LoginModal: Component<{
<Switch>
<Match when={step() === 'login'}>
<Modal open={props.open} onClose={onAbort}>
<div id={props.id} class={styles.modal}>
<form id={props.id} class={styles.modal} onSubmit={onSubmit}>
<button class={styles.xClose} onClick={onAbort}>
<div class={styles.iconClose}></div>
</button>
<div class={styles.title}>
{intl.formatMessage(tLogin.title)}
</div>
<div class={styles.title}>{intl.formatMessage(tLogin.title)}</div>
<div class={styles.description}>
{intl.formatMessage(tLogin.description)}
</div>
Expand All @@ -98,21 +97,24 @@ const LoginModal: Component<{
ref={loginInput}
type="password"
value={enteredKey()}
onKeyUp={onKeyUp}
onChange={setEnteredKey}
validationState={enteredKey().length === 0 || isValidNsec() ? 'valid' : 'invalid'}
validationState={
enteredKey().length === 0 || isValidNsec()
? 'valid'
: 'invalid'
}
errorMessage={intl.formatMessage(tLogin.invalidNsec)}
/>
</div>
<div class={styles.actions}>
<ButtonPrimary
onClick={onLogin}
type="submit"
disabled={enteredKey().length === 0 || !isValidNsec()}
>
{intl.formatMessage(tActions.login)}
</ButtonPrimary>
</div>
</div>
</form>
</Modal>
</Match>

Expand All @@ -128,6 +130,6 @@ const LoginModal: Component<{
</Match>
</Switch>
);
}
};

export default hookForDev(LoginModal);

0 comments on commit f8c5211

Please sign in to comment.