Skip to content
Snippets Groups Projects
Unverified Commit 9d27379b authored by Jed Fox's avatar Jed Fox Committed by GitHub
Browse files

Move big input component into Input.js, port some of the manager app to TS (#1431)

parent b8454682
No related branches found
No related tags found
No related merge requests found
...@@ -4,25 +4,39 @@ import React, { ...@@ -4,25 +4,39 @@ import React, {
useCallback, useCallback,
useEffect, useEffect,
useContext, useContext,
type ReactNode,
} from 'react'; } from 'react';
import { send } from 'loot-core/src/platform/client/fetch'; import { send } from 'loot-core/src/platform/client/fetch';
const ServerContext = createContext({}); type ServerContextValue = {
url: string | null;
version: string;
setURL: (
url: string,
opts?: { validate?: boolean },
) => Promise<{ error?: string }>;
};
const ServerContext = createContext<ServerContextValue>({
url: null,
version: '',
setURL: () => Promise.reject(new Error('ServerContext not initialized')),
});
export const useServerURL = () => useContext(ServerContext).url; export const useServerURL = () => useContext(ServerContext).url;
export const useServerVersion = () => useContext(ServerContext).version; export const useServerVersion = () => useContext(ServerContext).version;
export const useSetServerURL = () => useContext(ServerContext).setURL; export const useSetServerURL = () => useContext(ServerContext).setURL;
async function getServerVersion() { async function getServerVersion() {
let { error, version } = await send('get-server-version'); let result = await send('get-server-version');
if (error) { if ('version' in result) {
return ''; return result.version;
} }
return version; return '';
} }
export function ServerProvider({ children }) { export function ServerProvider({ children }: { children: ReactNode }) {
let [serverURL, setServerURL] = useState(''); let [serverURL, setServerURL] = useState('');
let [version, setVersion] = useState(''); let [version, setVersion] = useState('');
...@@ -35,7 +49,7 @@ export function ServerProvider({ children }) { ...@@ -35,7 +49,7 @@ export function ServerProvider({ children }) {
}, []); }, []);
let setURL = useCallback( let setURL = useCallback(
async (url, opts = {}) => { async (url: string, opts: { validate?: boolean } = {}) => {
let { error } = await send('set-server-url', { ...opts, url }); let { error } = await send('set-server-url', { ...opts, url });
if (!error) { if (!error) {
setServerURL(await send('get-server-url')); setServerURL(await send('get-server-url'));
......
...@@ -23,14 +23,14 @@ type InputProps = HTMLPropsWithStyle<HTMLInputElement> & { ...@@ -23,14 +23,14 @@ type InputProps = HTMLPropsWithStyle<HTMLInputElement> & {
focused?: boolean; focused?: boolean;
}; };
const Input = ({ export default function Input({
style, style,
inputRef, inputRef,
onEnter, onEnter,
onUpdate, onUpdate,
focused, focused,
...nativeProps ...nativeProps
}: InputProps) => { }: InputProps) {
let ref = useRef(); let ref = useRef();
useProperFocus(ref, focused); useProperFocus(ref, focused);
...@@ -68,6 +68,22 @@ const Input = ({ ...@@ -68,6 +68,22 @@ const Input = ({
}} }}
/> />
); );
}; }
export default Input; export function BigInput(props: InputProps) {
return (
<Input
{...props}
style={[
{
padding: 10,
fontSize: 15,
border: 'none',
...styles.shadow,
':focus': { border: 'none', ...styles.shadow },
},
props.style,
]}
/>
);
}
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { createBudget } from 'loot-core/src/client/actions/budgets';
import { signOut, loggedIn } from 'loot-core/src/client/actions/user';
import { import {
isNonProductionEnvironment, isNonProductionEnvironment,
isElectron, isElectron,
} from 'loot-core/src/shared/environment'; } from 'loot-core/src/shared/environment';
import { useActions } from '../../hooks/useActions';
import { useSetThemeColor } from '../../hooks/useSetThemeColor'; import { useSetThemeColor } from '../../hooks/useSetThemeColor';
import { colors } from '../../style'; import { colors } from '../../style';
import Button, { ButtonWithLoading } from '../common/Button'; import Button, { ButtonWithLoading } from '../common/Button';
import { BigInput } from '../common/Input';
import Text from '../common/Text'; import Text from '../common/Text';
import View from '../common/View'; import View from '../common/View';
import { useServerURL, useSetServerURL } from '../ServerContext'; import { useServerURL, useSetServerURL } from '../ServerContext';
import { Title, Input } from './subscribe/common'; import { Title } from './subscribe/common';
export default function ConfigServer() { export default function ConfigServer() {
useSetThemeColor(colors.p5); useSetThemeColor(colors.p5);
let dispatch = useDispatch(); let { createBudget, signOut, loggedIn } = useActions();
let navigate = useNavigate(); let navigate = useNavigate();
let [url, setUrl] = useState(''); let [url, setUrl] = useState('');
let currentUrl = useServerURL(); let currentUrl = useServerURL();
...@@ -29,9 +28,9 @@ export default function ConfigServer() { ...@@ -29,9 +28,9 @@ export default function ConfigServer() {
setUrl(currentUrl); setUrl(currentUrl);
}, [currentUrl]); }, [currentUrl]);
let [loading, setLoading] = useState(false); let [loading, setLoading] = useState(false);
let [error, setError] = useState(null); let [error, setError] = useState<string | null>(null);
function getErrorMessage(error) { function getErrorMessage(error: string) {
switch (error) { switch (error) {
case 'network-failure': case 'network-failure':
return 'Server is not running at this URL. Make sure you have HTTPS set up properly.'; return 'Server is not running at this URL. Make sure you have HTTPS set up properly.';
...@@ -59,7 +58,7 @@ export default function ConfigServer() { ...@@ -59,7 +58,7 @@ export default function ConfigServer() {
setUrl('https://' + url); setUrl('https://' + url);
setError(error); setError(error);
} else { } else {
await dispatch(signOut()); await signOut();
navigate('/'); navigate('/');
} }
setLoading(false); setLoading(false);
...@@ -68,7 +67,7 @@ export default function ConfigServer() { ...@@ -68,7 +67,7 @@ export default function ConfigServer() {
setError(error); setError(error);
} else { } else {
setLoading(false); setLoading(false);
await dispatch(signOut()); await signOut();
navigate('/'); navigate('/');
} }
} }
...@@ -79,13 +78,13 @@ export default function ConfigServer() { ...@@ -79,13 +78,13 @@ export default function ConfigServer() {
async function onSkip() { async function onSkip() {
await setServerUrl(null); await setServerUrl(null);
await dispatch(loggedIn()); await loggedIn();
navigate('/'); navigate('/');
} }
async function onCreateTestFile() { async function onCreateTestFile() {
await setServerUrl(null); await setServerUrl(null);
await dispatch(createBudget({ testMode: true })); await createBudget({ testMode: true });
window.__navigate('/'); window.__navigate('/');
} }
...@@ -134,11 +133,11 @@ export default function ConfigServer() { ...@@ -134,11 +133,11 @@ export default function ConfigServer() {
onSubmit(); onSubmit();
}} }}
> >
<Input <BigInput
autoFocus={true} autoFocus={true}
placeholder={'https://example.com'} placeholder="https://example.com"
value={url || ''} value={url || ''}
onChange={e => setUrl(e.target.value)} onUpdate={setUrl}
style={{ flex: 1, marginRight: 10 }} style={{ flex: 1, marginRight: 10 }}
/> />
<ButtonWithLoading <ButtonWithLoading
......
...@@ -30,7 +30,7 @@ export default function ServerURL() { ...@@ -30,7 +30,7 @@ export default function ServerURL() {
<strong>No server configured</strong> <strong>No server configured</strong>
)} )}
</Text> </Text>
<AnchorLink bare to="/config-server" style={{ marginLeft: 15 }}> <AnchorLink to="/config-server" style={{ marginLeft: 15 }}>
Change Change
</AnchorLink> </AnchorLink>
</View> </View>
......
import React, { type ChangeEvent, useState } from 'react'; import React, { type ChangeEvent, useState } from 'react';
import { ButtonWithLoading } from '../../common/Button'; import { ButtonWithLoading } from '../../common/Button';
import { BigInput } from '../../common/Input';
import View from '../../common/View'; import View from '../../common/View';
import { Input } from './common';
export function ConfirmPasswordForm({ buttons, onSetPassword, onError }) { export function ConfirmPasswordForm({ buttons, onSetPassword, onError }) {
let [password1, setPassword1] = useState(''); let [password1, setPassword1] = useState('');
let [password2, setPassword2] = useState(''); let [password2, setPassword2] = useState('');
...@@ -40,7 +39,7 @@ export function ConfirmPasswordForm({ buttons, onSetPassword, onError }) { ...@@ -40,7 +39,7 @@ export function ConfirmPasswordForm({ buttons, onSetPassword, onError }) {
}} }}
onSubmit={onSubmit} onSubmit={onSubmit}
> >
<Input <BigInput
autoFocus={true} autoFocus={true}
placeholder="Password" placeholder="Password"
type={showPassword ? 'text' : 'password'} type={showPassword ? 'text' : 'password'}
...@@ -50,7 +49,7 @@ export function ConfirmPasswordForm({ buttons, onSetPassword, onError }) { ...@@ -50,7 +49,7 @@ export function ConfirmPasswordForm({ buttons, onSetPassword, onError }) {
} }
onEnter={onSubmit} onEnter={onSubmit}
/> />
<Input <BigInput
placeholder="Confirm password" placeholder="Confirm password"
type={showPassword ? 'text' : 'password'} type={showPassword ? 'text' : 'password'}
value={password2} value={password2}
......
...@@ -7,10 +7,11 @@ import { send } from 'loot-core/src/platform/client/fetch'; ...@@ -7,10 +7,11 @@ import { send } from 'loot-core/src/platform/client/fetch';
import { colors } from '../../../style'; import { colors } from '../../../style';
import Button, { ButtonWithLoading } from '../../common/Button'; import Button, { ButtonWithLoading } from '../../common/Button';
import { BigInput } from '../../common/Input';
import Text from '../../common/Text'; import Text from '../../common/Text';
import View from '../../common/View'; import View from '../../common/View';
import { useBootstrapped, Title, Input } from './common'; import { useBootstrapped, Title } from './common';
export default function Login() { export default function Login() {
let dispatch = useDispatch(); let dispatch = useDispatch();
...@@ -88,7 +89,7 @@ export default function Login() { ...@@ -88,7 +89,7 @@ export default function Login() {
style={{ display: 'flex', flexDirection: 'row', marginTop: 30 }} style={{ display: 'flex', flexDirection: 'row', marginTop: 30 }}
onSubmit={onSubmit} onSubmit={onSubmit}
> >
<Input <BigInput
autoFocus={true} autoFocus={true}
placeholder="Password" placeholder="Password"
type="password" type="password"
......
import React, { import React, { useEffect, useState } from 'react';
type ComponentProps,
forwardRef,
useEffect,
useState,
} from 'react';
import { useNavigate, useLocation } from 'react-router-dom'; import { useNavigate, useLocation } from 'react-router-dom';
import { send } from 'loot-core/src/platform/client/fetch'; import { send } from 'loot-core/src/platform/client/fetch';
import { colors, styles } from '../../../style'; import { colors } from '../../../style';
import BaseInput from '../../common/Input';
import { useSetServerURL } from '../../ServerContext'; import { useSetServerURL } from '../../ServerContext';
// There are two URLs that dance with each other: `/login` and // There are two URLs that dance with each other: `/login` and
...@@ -92,22 +86,3 @@ export function Title({ text }: TitleProps) { ...@@ -92,22 +86,3 @@ export function Title({ text }: TitleProps) {
</h1> </h1>
); );
} }
type InputProps = ComponentProps<typeof BaseInput>;
export const Input = forwardRef<HTMLInputElement, InputProps>((props, ref) => {
return (
<BaseInput
{...props}
style={[
{
padding: 10,
fontSize: 15,
border: 'none',
...styles.shadow,
':focus': { border: 'none', ...styles.shadow },
},
props.style,
]}
/>
);
});
...@@ -282,9 +282,12 @@ export interface ServerHandlers { ...@@ -282,9 +282,12 @@ export interface ServerHandlers {
'get-server-version': () => Promise<{ error?: string } | { version: string }>; 'get-server-version': () => Promise<{ error?: string } | { version: string }>;
'get-server-url': () => Promise<unknown>; 'get-server-url': () => Promise<string | null>;
'set-server-url': (arg: { url; validate }) => Promise<unknown>; 'set-server-url': (arg: {
url: string;
validate?: boolean;
}) => Promise<{ error?: string }>;
sync: () => Promise< sync: () => Promise<
| { error: { message: string; reason: string; meta: unknown } } | { error: { message: string; reason: string; meta: unknown } }
......
---
category: Maintenance
authors: [j-f1]
---
Move big input component into Input.js, port some of the manager app to TS
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment