Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

♻️ moving P, useStableCallback, AnchorLink common components #1413

Merged
merged 2 commits into from
Jul 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions packages/desktop-client/src/components/FatalError.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import {
Text,
Block,
Modal,
P,
LinkButton,
Button,
ExternalLink,
} from './common';
import Paragraph from './common/Paragraph';
import { Checkbox } from './forms';

class FatalError extends Component {
Expand Down Expand Up @@ -112,20 +112,22 @@ class FatalError extends Component {
<Modal isCurrent={true} showClose={false} title="Fatal Error">
{() => (
<View style={{ maxWidth: 500 }}>
<P>There was an unrecoverable error in the UI. Sorry!</P>
<P>
<Paragraph>
There was an unrecoverable error in the UI. Sorry!
</Paragraph>
<Paragraph>
If this error persists, please get{' '}
<ExternalLink to="https://actualbudget.org/contact">
in touch
</ExternalLink>{' '}
so it can be investigated.
</P>
<P>
</Paragraph>
<Paragraph>
<Button onClick={() => window.Actual.relaunch()}>
{buttonText}
</Button>
</P>
<P isLast={true} style={{ fontSize: 11 }}>
</Paragraph>
<Paragraph isLast={true} style={{ fontSize: 11 }}>
<LinkButton onClick={() => this.setState({ showError: true })}>
Show Error
</LinkButton>
Expand All @@ -140,7 +142,7 @@ class FatalError extends Component {
{error.stack}
</Block>
)}
</P>
</Paragraph>
</View>
)}
</Modal>
Expand All @@ -155,13 +157,13 @@ function SharedArrayBufferOverride() {

return expanded ? (
<>
<P style={{ marginTop: 10 }}>
<Paragraph style={{ marginTop: 10 }}>
Actual uses <code>SharedArrayBuffer</code> to allow usage from multiple
tabs at once and to ensure correct behavior when switching files. While
it can run without access to <code>SharedArrayBuffer</code>, you may
encounter data loss or notice multiple budget files being merged with
each other.
</P>
</Paragraph>
<label
style={{ display: 'flex', alignItems: 'center', marginBottom: 10 }}
>
Expand Down
14 changes: 7 additions & 7 deletions packages/desktop-client/src/components/Titlebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ import {
Button,
ButtonWithLoading,
Tooltip,
P,
ExternalLink,
} from './common';
import Paragraph from './common/Paragraph';
import { useSidebar } from './FloatableSidebar';
import LoggedInUser from './LoggedInUser';
import { useServerURL } from './ServerContext';
Expand Down Expand Up @@ -240,7 +240,7 @@ function BudgetTitlebar() {
maxWidth: 400,
}}
>
<P>
<Paragraph>
You are currently using a{' '}
<Text style={{ fontWeight: 600 }}>
{budgetType === 'report'
Expand All @@ -249,8 +249,8 @@ function BudgetTitlebar() {
.
</Text>{' '}
Switching will not lose any data and you can always switch back.
</P>
<P>
</Paragraph>
<Paragraph>
<ButtonWithLoading
type="primary"
loading={loading}
Expand All @@ -261,15 +261,15 @@ function BudgetTitlebar() {
? 'Rollover budget'
: 'Report budget'}
</ButtonWithLoading>
</P>
<P isLast={true}>
</Paragraph>
<Paragraph isLast={true}>
<ExternalLink
to="https://actualbudget.org/docs/experimental/report-budget"
linkColor="muted"
>
How do these types of budgeting work?
</ExternalLink>
</P>
</Paragraph>
</Tooltip>
)}
</View>
Expand Down
70 changes: 5 additions & 65 deletions packages/desktop-client/src/components/common.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
import React, {
useRef,
useLayoutEffect,
useCallback,
type ComponentProps,
type ReactNode,
forwardRef,
} from 'react';
import { NavLink, useMatch, useNavigate } from 'react-router-dom';
import React, { type ComponentProps, type ReactNode, forwardRef } from 'react';
import { useMatch, useNavigate } from 'react-router-dom';

import { type CSSProperties, css } from 'glamor';
import { type CSSProperties } from 'glamor';

import { styles, colors } from '../style';
import type { HTMLPropsWithStyle } from '../types/utils';
import { colors } from '../style';

import Button from './common/Button';

export { default as AlignedText } from './common/AlignedText';
export { default as AnchorLink } from './common/AnchorLink';
export { default as Block } from './common/Block';
export { default as Button, ButtonWithLoading } from './common/Button';
export { default as Card } from './common/Card';
Expand All @@ -38,45 +31,6 @@ export { default as TextOneLine } from './common/TextOneLine';
export { default as View } from './common/View';
export { default as LinkButton } from './common/LinkButton';

type UseStableCallbackArg = (...args: unknown[]) => unknown;

export const useStableCallback = (callback: UseStableCallbackArg) => {
const callbackRef = useRef<UseStableCallbackArg>();
const memoCallback = useCallback(
(...args) => callbackRef.current && callbackRef.current(...args),
[],
);
useLayoutEffect(() => {
callbackRef.current = callback;
});
return memoCallback;
};

type AnchorLinkProps = {
to: string;
style?: CSSProperties;
activeStyle?: CSSProperties;
children?: ReactNode;
};

export function AnchorLink({
to,
style,
activeStyle,
children,
}: AnchorLinkProps) {
let match = useMatch({ path: to });

return (
<NavLink
to={to}
{...css([styles.smallText, style, match ? activeStyle : null])}
>
{children}
</NavLink>
);
}

let externalLinkColors = {
purple: colors.p4,
blue: colors.b4,
Expand Down Expand Up @@ -131,19 +85,5 @@ export function ButtonLink({
);
}

type PProps = HTMLPropsWithStyle<HTMLDivElement> & {
isLast?: boolean;
};
export function P({ style, isLast, children, ...props }: PProps) {
return (
<div
{...props}
{...css(!isLast && { marginBottom: 15 }, style, { lineHeight: '1.5em' })}
>
{children}
</div>
);
}

export * from './tooltips';
export { useTooltip } from './tooltips';
31 changes: 31 additions & 0 deletions packages/desktop-client/src/components/common/AnchorLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { type ReactNode } from 'react';
import { NavLink, useMatch } from 'react-router-dom';

import { type CSSProperties, css } from 'glamor';

import { styles } from '../../style';

type AnchorLinkProps = {
to: string;
style?: CSSProperties;
activeStyle?: CSSProperties;
children?: ReactNode;
};

export default function AnchorLink({
to,
style,
activeStyle,
children,
}: AnchorLinkProps) {
let match = useMatch({ path: to });

return (
<NavLink
to={to}
{...css([styles.smallText, style, match ? activeStyle : null])}
>
{children}
</NavLink>
);
}
23 changes: 23 additions & 0 deletions packages/desktop-client/src/components/common/Paragraph.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { css } from 'glamor';

import { type HTMLPropsWithStyle } from '../../types/utils';

type ParagraphProps = HTMLPropsWithStyle<HTMLDivElement> & {
isLast?: boolean;
};

export default function Paragraph({
style,
isLast,
children,
...props
}: ParagraphProps) {
return (
<div
{...props}
{...css(!isLast && { marginBottom: 15 }, style, { lineHeight: '1.5em' })}
>
{children}
</div>
);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';

import { Modal, P, View } from '../common';
import { Modal, View } from '../common';
import Paragraph from '../common/Paragraph';

export default function GoCardlessLink() {
window.close();
Expand All @@ -9,11 +10,11 @@ export default function GoCardlessLink() {
<Modal isCurrent={true} showClose={false} title="Account sync">
{() => (
<View style={{ maxWidth: 500 }}>
<P>Please wait...</P>
<P>
<Paragraph>Please wait...</Paragraph>
<Paragraph>
The window should close automatically. If nothing happend you can
close this window or tab.
</P>
</Paragraph>
</View>
)}
</Modal>
Expand Down
11 changes: 7 additions & 4 deletions packages/desktop-client/src/components/manager/ImportActual.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { useDispatch } from 'react-redux';
import { importBudget } from 'loot-core/src/client/actions/budgets';

import { styles, colors } from '../../style';
import { View, Block, Modal, ButtonWithLoading, P } from '../common';
import { View, Block, Modal, ButtonWithLoading } from '../common';
import Paragraph from '../common/Paragraph';

function getErrorMessage(error) {
switch (error) {
Expand Down Expand Up @@ -61,14 +62,16 @@ function Import({ modalProps }) {
)}

<View style={{ '& > div': { lineHeight: '1.7em' } }}>
<P>
<Paragraph>
You can import data from another Actual account or instance. First
export your data from a different account, and it will give you a
compressed file. This file is a simple zip file that contains the{' '}
<code>db.sqlite</code> and <code>metadata.json</code> files.
</P>
</Paragraph>

<P>Select one of these compressed files and import it here.</P>
<Paragraph>
Select one of these compressed files and import it here.
</Paragraph>

<View style={{ alignSelf: 'center' }}>
<ButtonWithLoading
Expand Down
11 changes: 6 additions & 5 deletions packages/desktop-client/src/components/manager/ImportYNAB4.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { useDispatch } from 'react-redux';
import { importBudget } from 'loot-core/src/client/actions/budgets';

import { styles, colors } from '../../style';
import { View, Block, Modal, ButtonWithLoading, P } from '../common';
import { View, Block, Modal, ButtonWithLoading } from '../common';
import Paragraph from '../common/Paragraph';

function getErrorMessage(error) {
switch (error) {
Expand Down Expand Up @@ -49,18 +50,18 @@ function Import({ modalProps }) {
)}

<View style={{ alignItems: 'center' }}>
<P>
<Paragraph>
To import data from YNAB4, locate where your YNAB4 data is stored.
It is usually in your Documents folder under YNAB. Your data is a
directory inside that with the <code>.ynab4</code> suffix.
</P>
<P>
</Paragraph>
<Paragraph>
When you’ve located your data,{' '}
<strong>compress it into a zip file</strong>. On macOS,
right-click the folder and select “Compress”. On Windows,
right-click and select “Send to &rarr; Compressed (zipped)
folder”. Upload the zipped folder for importing.
</P>
</Paragraph>
<View>
<ButtonWithLoading
type="primary"
Expand Down
18 changes: 6 additions & 12 deletions packages/desktop-client/src/components/manager/ImportYNAB5.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,8 @@ import { useDispatch } from 'react-redux';
import { importBudget } from 'loot-core/src/client/actions/budgets';

import { styles, colors } from '../../style';
import {
View,
Block,
Modal,
ButtonWithLoading,
P,
ExternalLink,
} from '../common';
import { View, Block, Modal, ButtonWithLoading, ExternalLink } from '../common';
import Paragraph from '../common/Paragraph';

function getErrorMessage(error) {
switch (error) {
Expand Down Expand Up @@ -60,20 +54,20 @@ function Import({ modalProps }) {
<View
style={{ alignItems: 'center', '& > div': { lineHeight: '1.7em' } }}
>
<P>
<Paragraph>
<ExternalLink to="https://actualbudget.org/docs/migration/nynab">
Read here
</ExternalLink>{' '}
for instructions on how to migrate your data from YNAB. You need
to export your data as JSON, and that page explains how to do
that.
</P>
<P>
</Paragraph>
<Paragraph>
Once you have exported your data, select the file and Actual will
import it. Budgets may not match up exactly because things work
slightly differently, but you should be able to fix up any
problems.
</P>
</Paragraph>
<View>
<ButtonWithLoading
type="primary"
Expand Down
Loading
Loading