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

Remove usage of Formik (#1212)

parent df74e6dd
No related branches found
No related tags found
No related merge requests found
......@@ -30,7 +30,6 @@
"debounce": "^1.2.0",
"downshift": "7.6.0",
"focus-visible": "^4.1.1",
"formik": "^0.11.10",
"glamor": "^2.20.40",
"hotkeys-js": "3.10.3",
"inter-ui": "^3.19.3",
......
......@@ -129,11 +129,11 @@ type LinkProps = ComponentProps<typeof Button>;
export function LinkButton({ style, children, ...nativeProps }: LinkProps) {
return (
<Button
{...css(
style={[
{
textDecoration: 'none',
color: styles.textColor,
backgroundColor: 'transparent !important',
backgroundColor: 'transparent',
display: 'inline',
border: 0,
cursor: 'pointer',
......@@ -149,7 +149,7 @@ export function LinkButton({ style, children, ...nativeProps }: LinkProps) {
},
styles.smallText,
style,
)}
]}
{...nativeProps}
>
{children}
......
import React, { useState } from 'react';
import { Formik } from 'formik';
import { integerToCurrency } from 'loot-core/src/shared/util';
import { colors } from '../../style';
......@@ -52,6 +50,11 @@ function CloseAccount({
modalProps,
}) {
let [loading, setLoading] = useState(false);
let [transfer, setTransfer] = useState('');
let [category, setCategory] = useState('');
let [transferError, setTransferError] = useState(false);
let [categoryError, setCategoryError] = useState(false);
let filtered = accounts.filter(a => a.id !== account.id);
let onbudget = filtered.filter(a => a.offbudget === 0);
......@@ -79,153 +82,138 @@ function CloseAccount({
</span>
)}
</P>
<Formik
validateOnChange={false}
initialValues={{ transfer: '', category: '' }}
onSubmit={(values, { setErrors }) => {
const errors = {};
if (balance !== 0 && values.transfer === '') {
errors.transfer = 'required';
}
if (
needsCategory(account, values.transfer, accounts) &&
values.category === ''
) {
errors.category = 'required';
}
setErrors(errors);
<form
onSubmit={event => {
event.preventDefault();
let transferError = balance !== 0 && transfer === '';
setTransferError(transferError);
let categoryError =
needsCategory(account, transfer, accounts) && category === '';
setCategoryError(categoryError);
if (Object.keys(errors).length === 0) {
if (!transferError && !categoryError) {
setLoading(true);
actions
.closeAccount(
account.id,
values.transfer || null,
values.category || null,
)
.closeAccount(account.id, transfer || null, category || null)
.then(() => {
modalProps.onClose();
});
}
}}
render={({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit,
isSubmitting,
setFieldValue,
}) => (
<form onSubmit={handleSubmit}>
{balance !== 0 && (
<View>
>
{balance !== 0 && (
<View>
<P>
This account has a balance of{' '}
<strong>{integerToCurrency(balance)}</strong>. To close this
account, select a different account to transfer this balance
to:
</P>
<Select
value={transfer}
onChange={event => {
setTransfer(event.target.value);
if (transferError && event.target.value) {
setTransferError(false);
}
}}
style={{ width: 200, marginBottom: 15 }}
>
<option value="">Select account...</option>
<optgroup label="For Budget">
{onbudget.map(acct => (
<option key={acct.id} value={acct.id}>
{acct.name}
</option>
))}
</optgroup>
<optgroup label="Off Budget">
{offbudget.map(acct => (
<option key={acct.id} value={acct.id}>
{acct.name}
</option>
))}
</optgroup>
</Select>
{transferError && (
<FormError style={{ marginBottom: 15 }}>
Transfer is required
</FormError>
)}
{needsCategory(account, transfer, accounts) && (
<View style={{ marginBottom: 15 }}>
<P>
This account has a balance of{' '}
<strong>{integerToCurrency(balance)}</strong>. To close
this account, select a different account to transfer this
balance to:
Since you are transferring the balance from a budgeted
account to an off-budget account, this transaction must be
categorized. Select a category:
</P>
<Select
name="transfer"
value={values.transfer}
onChange={handleChange}
onBlur={handleBlur}
style={{ width: 200, marginBottom: 15 }}
>
<option value="">Select account...</option>
<optgroup label="For Budget">
{onbudget.map(acct => (
<option key={acct.id} value={acct.id}>
{acct.name}
</option>
))}
</optgroup>
<optgroup label="Off Budget">
{offbudget.map(acct => (
<option key={acct.id} value={acct.id}>
{acct.name}
</option>
))}
</optgroup>
</Select>
{errors.transfer && (
<FormError style={{ marginBottom: 15 }}>
Transfer is required
</FormError>
<CategorySelect
categoryGroups={categoryGroups}
value={category}
onChange={event => {
setCategory(event.target.value);
if (categoryError && event.target.value) {
setCategoryError(false);
}
}}
style={{ width: 200 }}
/>
{categoryError && (
<FormError>Category is required</FormError>
)}
{needsCategory(account, values.transfer, accounts) && (
<View style={{ marginBottom: 15 }}>
<P>
Since you are transferring the balance from a budgeted
account to an off-budget account, this transaction
must be categorized. Select a category:
</P>
<CategorySelect
categoryGroups={categoryGroups}
name="category"
value={values.category}
onChange={handleChange}
onBlur={handleBlur}
style={{ width: 200 }}
/>
{errors.category && (
<FormError>Category is required</FormError>
)}
</View>
)}
</View>
)}
{!canDelete && (
<View style={{ marginBottom: 15 }}>
<Text style={{ fontSize: 12 }}>
You can also{' '}
<LinkButton
onClick={() => {
setLoading(true);
actions
.forceCloseAccount(account.id)
.then(() => modalProps.onClose());
}}
style={{ color: colors.r6 }}
>
force close
</LinkButton>{' '}
the account which will delete it and all its transactions
permanently. Doing so may change your budget unexpectedly
since money in it may vanish.
</Text>
</View>
)}
</View>
)}
<View
style={{
flexDirection: 'row',
justifyContent: 'flex-end',
}}
>
<Button
type="submit"
style={{ marginRight: 10 }}
onClick={modalProps.onClose}
{!canDelete && (
<View style={{ marginBottom: 15 }}>
<Text style={{ fontSize: 12 }}>
You can also{' '}
<LinkButton
onClick={() => {
setLoading(true);
actions
.forceCloseAccount(account.id)
.then(() => modalProps.onClose());
}}
style={{ color: colors.r6 }}
>
Cancel
</Button>
<Button type="submit" primary>
Close Account
</Button>
</View>
</form>
force close
</LinkButton>{' '}
the account which will delete it and all its transactions
permanently. Doing so may change your budget unexpectedly
since money in it may vanish.
</Text>
</View>
)}
/>
<View
style={{
flexDirection: 'row',
justifyContent: 'flex-end',
}}
>
<Button
type="submit"
style={{ marginRight: 10 }}
onClick={modalProps.onClose}
>
Cancel
</Button>
<Button type="submit" primary>
Close Account
</Button>
</View>
</form>
</View>
)}
</Modal>
......
import React from 'react';
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { Formik } from 'formik';
import { toRelaxedNumber } from 'loot-core/src/shared/util';
import { colors } from '../../style';
......@@ -21,140 +19,142 @@ import {
function CreateLocalAccount({ modalProps, actions }) {
let navigate = useNavigate();
let [name, setName] = useState('');
let [offbudget, setOffbudget] = useState(false);
let [balance, setBalance] = useState('0');
let [nameError, setNameError] = useState(false);
let [balanceError, setBalanceError] = useState(false);
let validateBalance = balance => !isNaN(parseFloat(balance));
return (
<Modal title="Create Local Account" {...modalProps} showBack={false}>
{() => (
<View>
<Formik
validateOnChange={false}
initialValues={{ name: '', balance: '0' }}
validate={() => ({})}
onSubmit={async (values, { setErrors }) => {
const errors = {};
if (!values.name) {
errors.name = 'required';
}
if (isNaN(parseFloat(values.balance))) {
errors.balance = 'format';
}
setErrors(errors);
<form
onSubmit={async event => {
event.preventDefault();
let nameError = !name;
setNameError(nameError);
if (Object.keys(errors).length === 0) {
let balanceError = !validateBalance(balance);
setBalanceError(balanceError);
if (!nameError && !balanceError) {
modalProps.onClose();
let id = await actions.createAccount(
values.name,
toRelaxedNumber(values.balance),
values.offbudget,
name,
toRelaxedNumber(balance),
offbudget,
);
navigate('/accounts/' + id);
}
}}
render={({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit,
isSubmitting,
setFieldValue,
}) => (
<form onSubmit={handleSubmit}>
<InlineField label="Name" width="75%">
<InitialFocus>
<Input
name="name"
value={values.name}
onChange={handleChange}
onBlur={handleBlur}
style={{ flex: 1 }}
/>
</InitialFocus>
</InlineField>
{errors.name && (
<FormError style={{ marginLeft: 75 }}>
Name is required
</FormError>
)}
>
<InlineField label="Name" width="75%">
<InitialFocus>
<Input
name="name"
value={name}
onChange={event => setName(event.target.value)}
onBlur={event => {
let name = event.target.value.trim();
setName(name);
if (name && nameError) {
setNameError(false);
}
}}
style={{ flex: 1 }}
/>
</InitialFocus>
</InlineField>
{nameError && (
<FormError style={{ marginLeft: 75 }}>Name is required</FormError>
)}
<View
<View
style={{
width: '75%',
flexDirection: 'row',
justifyContent: 'flex-end',
}}
>
<View style={{ flexDirection: 'column' }}>
<label
style={{
width: '75%',
flexDirection: 'row',
userSelect: 'none',
textAlign: 'right',
width: '100%',
display: 'flex',
verticalAlign: 'center',
justifyContent: 'flex-end',
}}
htmlFor="offbudget"
>
<View style={{ flexDirection: 'column' }}>
<label
style={{
userSelect: 'none',
textAlign: 'right',
width: '100%',
display: 'flex',
verticalAlign: 'center',
justifyContent: 'flex-end',
}}
htmlFor="offbudget"
>
<input
id="offbudget"
name="offbudget"
type="checkbox"
checked={!!values.offbudget}
onChange={handleChange}
onBlur={handleBlur}
/>
Off-budget
</label>
<div
style={{
textAlign: 'right',
fontSize: '0.7em',
color: colors.n5,
marginTop: 3,
}}
>
<Text>
This cannot be changed later. <br /> {'\n'}
See{' '}
<ExternalLink
linkColor="muted"
to="https://actualbudget.org/docs/accounts/#off-budget-accounts"
>
Accounts Overview
</ExternalLink>{' '}
for more information.
</Text>
</div>
</View>
</View>
<InlineField label="Balance" width="75%">
<Input
name="balance"
value={values.balance}
onChange={handleChange}
onBlur={handleBlur}
style={{ flex: 1 }}
<input
id="offbudget"
name="offbudget"
type="checkbox"
checked={offbudget}
onChange={event => setOffbudget(event.target.checked)}
/>
</InlineField>
{errors.balance && (
<FormError style={{ marginLeft: 75 }}>
Balance must be a number
</FormError>
)}
Off-budget
</label>
<div
style={{
textAlign: 'right',
fontSize: '0.7em',
color: colors.n5,
marginTop: 3,
}}
>
<Text>
This cannot be changed later. <br /> {'\n'}
See{' '}
<ExternalLink
linkColor="muted"
to="https://actualbudget.org/docs/accounts/#off-budget-accounts"
>
Accounts Overview
</ExternalLink>{' '}
for more information.
</Text>
</div>
</View>
</View>
<ModalButtons>
<Button onClick={() => modalProps.onBack()} type="button">
Back
</Button>
<Button primary style={{ marginLeft: 10 }}>
Create
</Button>
</ModalButtons>
</form>
<InlineField label="Balance" width="75%">
<Input
name="balance"
value={balance}
onChange={event => setBalance(event.target.value)}
onBlur={event => {
let balance = event.target.value.trim();
setBalance(balance);
if (validateBalance(balance) && balanceError) {
setBalanceError(false);
}
}}
style={{ flex: 1 }}
/>
</InlineField>
{balanceError && (
<FormError style={{ marginLeft: 75 }}>
Balance must be a number
</FormError>
)}
/>
<ModalButtons>
<Button onClick={() => modalProps.onBack()} type="button">
Back
</Button>
<Button primary style={{ marginLeft: 10 }}>
Create
</Button>
</ModalButtons>
</form>
</View>
)}
</Modal>
......
---
category: Maintenance
authors: [j-f1]
---
Remove usage of Formik
......@@ -98,7 +98,6 @@ __metadata:
debounce: ^1.2.0
downshift: 7.6.0
focus-visible: ^4.1.1
formik: ^0.11.10
glamor: ^2.20.40
hotkeys-js: 3.10.3
inter-ui: ^3.19.3
......@@ -9410,21 +9409,6 @@ __metadata:
languageName: node
linkType: hard
 
"formik@npm:^0.11.10":
version: 0.11.11
resolution: "formik@npm:0.11.11"
dependencies:
lodash.clonedeep: ^4.5.0
lodash.isequal: 4.5.0
lodash.topath: 4.5.2
prop-types: ^15.5.10
warning: ^3.0.0
peerDependencies:
react: ">=15"
checksum: ce0fde6f1d87fa60afe3a025904e64b6394dccb48dd0739cd1d3aa987b00bad2e15584b03db7ed284b9260748db14fb36459f4768e7b93548e091223c406a0b8
languageName: node
linkType: hard
"forwarded@npm:0.2.0":
version: 0.2.0
resolution: "forwarded@npm:0.2.0"
......@@ -12257,13 +12241,6 @@ __metadata:
languageName: node
linkType: hard
 
"lodash.clonedeep@npm:^4.5.0":
version: 4.5.0
resolution: "lodash.clonedeep@npm:4.5.0"
checksum: 92c46f094b064e876a23c97f57f81fbffd5d760bf2d8a1c61d85db6d1e488c66b0384c943abee4f6af7debf5ad4e4282e74ff83177c9e63d8ff081a4837c3489
languageName: node
linkType: hard
"lodash.debounce@npm:^4.0.8":
version: 4.0.8
resolution: "lodash.debounce@npm:4.0.8"
......@@ -12278,7 +12255,7 @@ __metadata:
languageName: node
linkType: hard
 
"lodash.isequal@npm:4.5.0, lodash.isequal@npm:^4.5.0":
"lodash.isequal@npm:^4.5.0":
version: 4.5.0
resolution: "lodash.isequal@npm:4.5.0"
checksum: da27515dc5230eb1140ba65ff8de3613649620e8656b19a6270afe4866b7bd461d9ba2ac8a48dcc57f7adac4ee80e1de9f965d89d4d81a0ad52bb3eec2609644
......@@ -12306,13 +12283,6 @@ __metadata:
languageName: node
linkType: hard
 
"lodash.topath@npm:4.5.2":
version: 4.5.2
resolution: "lodash.topath@npm:4.5.2"
checksum: 04583e220f4bb1c4ac0008ff8f46d9cb4ddce0ea1090085790da30a41f4cb1b904d885cb73257fca619fa825cd96f9bb97c67d039635cb76056e18f5e08bfdee
languageName: node
linkType: hard
"lodash.uniq@npm:^4.5.0":
version: 4.5.0
resolution: "lodash.uniq@npm:4.5.0"
......@@ -18573,15 +18543,6 @@ __metadata:
languageName: node
linkType: hard
 
"warning@npm:^3.0.0":
version: 3.0.0
resolution: "warning@npm:3.0.0"
dependencies:
loose-envify: ^1.0.0
checksum: c9f99a12803aab81b29858e7dc3415bf98b41baee3a4c3acdeb680d98c47b6e17490f1087dccc54432deed5711a5ce0ebcda2b27e9b5eb054c32ae50acb4419c
languageName: node
linkType: hard
"warning@npm:^4.0.3":
version: 4.0.3
resolution: "warning@npm:4.0.3"
......
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