diff --git a/README.md b/README.md index 9adbd2c2..7cd23593 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,10 @@ The app is based on [Create React App](https://github.com/facebook/create-react- In the project directory, you can run: +### `npm install` + +Set up the development mode requirements. + ### `npm start` Runs the app in the development mode.
diff --git a/public/favicon-mask.svg b/public/favicon-mask.svg new file mode 100644 index 00000000..083de4aa --- /dev/null +++ b/public/favicon-mask.svg @@ -0,0 +1,70 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/public/favicon.ico b/public/favicon.ico index bf18080d..568bcba7 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/grouptabs-logo-192.png b/public/grouptabs-logo-192.png new file mode 100644 index 00000000..33a9c8db Binary files /dev/null and b/public/grouptabs-logo-192.png differ diff --git a/public/grouptabs-logo-512.png b/public/grouptabs-logo-512.png new file mode 100644 index 00000000..8e9299e4 Binary files /dev/null and b/public/grouptabs-logo-512.png differ diff --git a/public/index.html b/public/index.html index f2c19365..a01594a2 100644 --- a/public/index.html +++ b/public/index.html @@ -6,7 +6,8 @@ - + + Grouptabs @@ -16,7 +17,7 @@
- Grouptabs +

Grouptabs

diff --git a/public/logo192.png b/public/logo192.png deleted file mode 100644 index f71c8848..00000000 Binary files a/public/logo192.png and /dev/null differ diff --git a/public/logo512.png b/public/logo512.png deleted file mode 100644 index ac132437..00000000 Binary files a/public/logo512.png and /dev/null differ diff --git a/public/manifest.json b/public/manifest.json index 4da31600..a50d47fc 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -8,12 +8,12 @@ "type": "image/x-icon" }, { - "src": "logo192.png", + "src": "grouptabs-logo-192.png", "type": "image/png", "sizes": "192x192" }, { - "src": "logo512.png", + "src": "grouptabs-logo-512.png", "type": "image/png", "sizes": "512x512" } diff --git a/src/components/__snapshots__/createform.test.tsx.snap b/src/components/__snapshots__/createform.test.tsx.snap index 66371aca..003b7666 100644 --- a/src/components/__snapshots__/createform.test.tsx.snap +++ b/src/components/__snapshots__/createform.test.tsx.snap @@ -7,13 +7,15 @@ exports[`renders form 1`] = ` > diff --git a/src/components/__snapshots__/dateinput.test.tsx.snap b/src/components/__snapshots__/dateinput.test.tsx.snap index f03f6cf8..34a2d9b5 100644 --- a/src/components/__snapshots__/dateinput.test.tsx.snap +++ b/src/components/__snapshots__/dateinput.test.tsx.snap @@ -20,6 +20,7 @@ exports[`renders prefilled input 1`] = ` diff --git a/src/components/__snapshots__/directtransactioninput.test.tsx.snap b/src/components/__snapshots__/directtransactioninput.test.tsx.snap index 42e3ce0d..6bf60d99 100644 --- a/src/components/__snapshots__/directtransactioninput.test.tsx.snap +++ b/src/components/__snapshots__/directtransactioninput.test.tsx.snap @@ -24,7 +24,7 @@ exports[`renders empty 1`] = ` @@ -68,7 +68,7 @@ exports[`renders empty 1`] = ` @@ -100,7 +100,7 @@ exports[`renders prefilled 1`] = ` @@ -144,7 +144,7 @@ exports[`renders prefilled 1`] = ` diff --git a/src/components/__snapshots__/editentry.test.tsx.snap b/src/components/__snapshots__/editentry.test.tsx.snap index 2bae926b..ecb532a2 100644 --- a/src/components/__snapshots__/editentry.test.tsx.snap +++ b/src/components/__snapshots__/editentry.test.tsx.snap @@ -104,6 +104,7 @@ Array [ @@ -140,7 +141,7 @@ Array [ @@ -198,7 +199,7 @@ Array [ @@ -316,10 +317,11 @@ Array [ className="form-row-input" > @@ -363,7 +365,7 @@ Array [ >

Grouptabs @@ -375,7 +377,7 @@ Array [ className="create" onClick={[Function]} > - OK + Refresh , @@ -516,6 +518,7 @@ Array [ @@ -674,10 +677,11 @@ Array [ className="form-row-input" > @@ -686,12 +690,12 @@ Array [
- Delete transaction - +
, diff --git a/src/components/__snapshots__/form.test.tsx.snap b/src/components/__snapshots__/form.test.tsx.snap index d2528c68..ee409853 100644 --- a/src/components/__snapshots__/form.test.tsx.snap +++ b/src/components/__snapshots__/form.test.tsx.snap @@ -66,6 +66,7 @@ exports[`renders empty form 1`] = ` @@ -102,7 +103,7 @@ exports[`renders empty form 1`] = ` @@ -160,7 +161,7 @@ exports[`renders empty form 1`] = ` @@ -278,10 +279,11 @@ exports[`renders empty form 1`] = ` className="form-row-input" > @@ -359,6 +361,7 @@ exports[`renders prefilled form 1`] = ` @@ -396,7 +399,7 @@ exports[`renders prefilled form 1`] = ` @@ -440,7 +443,7 @@ exports[`renders prefilled form 1`] = ` @@ -532,10 +535,11 @@ exports[`renders prefilled form 1`] = ` className="form-row-input" > @@ -544,12 +548,12 @@ exports[`renders prefilled form 1`] = `
- Delete transaction - +
`; diff --git a/src/components/__snapshots__/importform.test.tsx.snap b/src/components/__snapshots__/importform.test.tsx.snap index 030699d9..394ac0bf 100644 --- a/src/components/__snapshots__/importform.test.tsx.snap +++ b/src/components/__snapshots__/importform.test.tsx.snap @@ -5,21 +5,17 @@ exports[`renders form 1`] = ` className="import-form" onSubmit={[Function]} > -
- Open shared tab: -

Grouptabs @@ -56,7 +56,7 @@ exports[`renders empty view with no tab selected 1`] = ` className="create" onClick={[Function]} > - OK + Refresh

@@ -107,7 +107,7 @@ exports[`renders missing tab info error 1`] = ` >

Grouptabs @@ -119,7 +119,7 @@ exports[`renders missing tab info error 1`] = ` className="create" onClick={[Function]} > - OK + Refresh @@ -168,59 +168,64 @@ exports[`renders summary and transaction list 1`] = `
- - - +
+ -12 +
+
-
- - - + +
  • +
    + 12 +
    +
    -
  • - - - -
    - Jan - - -11.7 -
    - Martin - - 11.7 -
    + Martin +
    + +
    -

    - Transactions -

    @@ -231,42 +236,40 @@ exports[`renders summary and transaction list 1`] = ` > 9/20/2020
    -
    - - - - - - - -
    - Gummibärchen -
    - - Martin: 22.8, - - Jan -
    -
    - 22.8 -
    -
    +
    +
    + Gummibärchen +
    +
    + + Martin 22.8 · + + Jan +
    +
    +
    + 22.8 +
    +
    - Total Spending: + Total spending: 22.8
    @@ -328,7 +331,7 @@ exports[`renders tab with no transactions 1`] = ` className="empty-info" >

    - A tab consists of transactions. When you add a transaction you also define the people that are part of it, the participants. + A tab consists of transactions. When you add a transaction you also define the participants.

    Start by adding your first transaction: diff --git a/src/components/__snapshots__/tabs.test.tsx.snap b/src/components/__snapshots__/tabs.test.tsx.snap index c886c582..e732f2a7 100644 --- a/src/components/__snapshots__/tabs.test.tsx.snap +++ b/src/components/__snapshots__/tabs.test.tsx.snap @@ -10,7 +10,7 @@ exports[`renders empty tab view 1`] = `

    Grouptabs @@ -24,14 +24,16 @@ exports[`renders empty tab view 1`] = ` className="empty-info" >

    - Track shared expenses in a group of people. Every group has its own tab like "Summer roadtrip" or "Badminton". + + Track expenses in a group of people! +

    - Start by creating your first tab: + Every group has a tab like "Summer roadtrip" or "Badminton team" – start by creating one!

    @@ -54,21 +58,35 @@ exports[`renders empty tab view 1`] = `
    -

    - Open shared tab -

    + + +
    +
    @@ -133,21 +158,35 @@ exports[`renders tab view 1`] = `
    -

    - Open shared tab -

    + + +
    +
    ); }; diff --git a/src/components/directtransactioninput.tsx b/src/components/directtransactioninput.tsx index b74b817f..167946e5 100644 --- a/src/components/directtransactioninput.tsx +++ b/src/components/directtransactioninput.tsx @@ -4,7 +4,7 @@ import { NEW_PARTICIPANT_OPTION } from "../util/transactionform"; import { control } from "../util/form"; import { PropsFromRedux } from "../app"; -const newParticipantOptionLabel = "New participant…"; +const newParticipantOptionLabel = "New participant …"; interface Props { data: TransactionFormState["direct"]; diff --git a/src/components/error.tsx b/src/components/error.tsx index 12ce4006..3bd9fdb7 100644 --- a/src/components/error.tsx +++ b/src/components/error.tsx @@ -1,5 +1,5 @@ import React, { memo, FunctionComponent } from "react"; -import logo from "../images/logo.png"; +import logo from "../images/grouptabs-logo.svg"; interface Props { error: { error: any; info: any }; @@ -10,7 +10,7 @@ const Error: FunctionComponent = () => {
    -

    Error

    +

    Grouptabs

    Oops, unfortunately an error occured.

    diff --git a/src/components/form.tsx b/src/components/form.tsx index f65576e5..b22f6ad5 100644 --- a/src/components/form.tsx +++ b/src/components/form.tsx @@ -139,8 +139,12 @@ const Form: FunctionComponent = (props) => { />

    - {showAllJoinedButton && (
    {props.mode === "edit" ? ( - + ) : null}
    diff --git a/src/components/importform.tsx b/src/components/importform.tsx index 98183747..005fdf39 100644 --- a/src/components/importform.tsx +++ b/src/components/importform.tsx @@ -25,20 +25,20 @@ const ImportForm: FunctionComponent = ({ return (
    -
    Open shared tab:
    ) => onTabIdChange(event.currentTarget.value) } + onFocus={(e) => (e.target.placeholder = "Tab ID …")} + onBlur={(e) => (e.target.placeholder = "Open shared tab")} />
    {remoteTabError}
    diff --git a/src/components/loaderror.tsx b/src/components/loaderror.tsx index fe285fa0..4c9b9ef2 100644 --- a/src/components/loaderror.tsx +++ b/src/components/loaderror.tsx @@ -1,5 +1,5 @@ import React, { memo, FunctionComponent } from "react"; -import logo from "../images/logo.png"; +import logo from "../images/grouptabs-logo.svg"; interface Props { message: string; @@ -21,7 +21,7 @@ const LoadError: FunctionComponent = ({ message, onOkClick }) => {

    Grouptabs

    {message}

    ); diff --git a/src/components/main.tsx b/src/components/main.tsx index fdc63b7f..03720e48 100644 --- a/src/components/main.tsx +++ b/src/components/main.tsx @@ -1,13 +1,5 @@ -import React, { - FunctionComponent, - useRef, - useState, - useEffect, - memo, - RefObject, -} from "react"; +import React, { FunctionComponent, useRef, memo } from "react"; // @ts-ignore -import SmoothScroll from "smooth-scroll"; import Loader from "./loader"; import Summary from "./summary"; import TransactionList from "./transactionlist"; @@ -32,85 +24,11 @@ interface Props { onDetailsClick: (tabId: string, transactionId: string) => void; } -const useTransactionHeadingScroller = ( - scrollContainerRef: RefObject, - transactionsHeadingRef: RefObject, - recheckDependencies: unknown[] -): { - transactionsHeadingIsOutOfViewport: boolean; - scrollToTransactionHeading: () => void; -} => { - const [ - transactionsHeadingIsOutOfViewport, - setTransactionsHeadingIsOutOfViewport, - ] = useState(false); - - // this ref is needed as the state updates unreliably - const transactionsHeadingIsOutOfViewportRef = useRef(false); - - const checkTransactionsHeadingVisibilityRef = useRef(() => { - if (!scrollContainerRef.current || !transactionsHeadingRef.current) { - return; - } - - const scrollContainer = scrollContainerRef.current; - const scrollBottomY = - scrollContainer.clientHeight + scrollContainer.scrollTop; - const headingY = transactionsHeadingRef.current.offsetTop; - const newTransactionsHeadingIsOutOfViewport = scrollBottomY < headingY + 60; - if ( - newTransactionsHeadingIsOutOfViewport !== - transactionsHeadingIsOutOfViewportRef.current - ) { - transactionsHeadingIsOutOfViewportRef.current = newTransactionsHeadingIsOutOfViewport; - setTransactionsHeadingIsOutOfViewport( - newTransactionsHeadingIsOutOfViewport - ); - } - }); - - const scroller = useRef(new SmoothScroll()); - - useEffect(() => { - const handler = checkTransactionsHeadingVisibilityRef.current; - const scrollContainer = scrollContainerRef.current; - scrollContainer?.addEventListener("scroll", handler); - window.addEventListener("resize", handler); - handler(); - - return () => { - scrollContainer?.removeEventListener("scroll", handler); - window.removeEventListener("resize", handler); - }; - }, [scrollContainerRef]); - - useEffect(() => { - setTimeout(checkTransactionsHeadingVisibilityRef.current); - }, recheckDependencies); // eslint-disable-line react-hooks/exhaustive-deps - - return { - transactionsHeadingIsOutOfViewport, - scrollToTransactionHeading: () => { - scroller.current.animateScroll(transactionsHeadingRef.current); - }, - }; -}; - const Main: FunctionComponent = (props) => { const contentContainerRef = useRef(null); - const transactionsHeadingRef = useRef(null); const [isScrolled, scrollContainerRef] = useScrollIndicator(); - const { - transactionsHeadingIsOutOfViewport, - scrollToTransactionHeading, - } = useTransactionHeadingScroller( - contentContainerRef, - transactionsHeadingRef, - [props.accounts] - ); - const handleNewEntryClick = () => { if (!props.tabId) { throw new Error("Tab ID missing."); @@ -140,9 +58,6 @@ const Main: FunctionComponent = (props) => {
    -

    - Transactions -

    = (props) => {

    A tab consists of transactions. When you add a transaction you also - define the people that are part of it, the participants. + define the participants.

    Start by adding your first transaction:

    @@ -209,14 +124,6 @@ const Main: FunctionComponent = (props) => { return (
    {renderHeader(!isLoading && !props.remoteTabError)} - {transactionsHeadingIsOutOfViewport && ( -

    - ▾ Transactions -

    - )}
    Math.round(amount * 100) / 100; + const round = (amount: number) => Math.round(amount); const getMaxAmount = (accounts: Account[]) => { let result = 0; @@ -23,10 +23,11 @@ function formatData(accounts: Account[]) { if (!maxAmount) { return { backgroundColor: "transparent" }; } - const color = amount < 0 ? [226, 91, 29] : [92, 226, 14]; - const opacity = Math.abs(amount) / maxAmount; + const color = amount < 0 ? [255, 68, 68] : [255, 255, 255]; + const opacity = amount < 0 ? Math.abs(amount) / maxAmount : 0; color.push(opacity); - const textColor = opacity > 0.6 ? "var(--dark-color)" : ""; + const textColor = + opacity > 0.6 && amount < 0 ? "var(--color-primary-opposite)" : ""; return { backgroundColor: `rgba(${color.join(",")})`, color: textColor }; }; @@ -41,16 +42,16 @@ function formatData(accounts: Account[]) { } const Summary: FunctionComponent = ({ accounts }) => ( - - - {formatData(accounts).map((account) => ( - - - - - ))} - -
    {account.participant}{account.amount}
    +
      + {formatData(accounts).map((account) => ( +
    1. +
      {account.amount}
      +
      + {account.participant} +
      +
    2. + ))} +
    ); export default memo(Summary); diff --git a/src/components/tablistbutton.tsx b/src/components/tablistbutton.tsx index cc37eb0f..95ea0fd8 100644 --- a/src/components/tablistbutton.tsx +++ b/src/components/tablistbutton.tsx @@ -7,9 +7,15 @@ interface Props { } const TabListButton: FunctionComponent = ({ data, onClick }) => { + console.log("test"); return ( ); }; diff --git a/src/components/tabs.tsx b/src/components/tabs.tsx index a2066ea8..2024d99d 100644 --- a/src/components/tabs.tsx +++ b/src/components/tabs.tsx @@ -1,9 +1,9 @@ -import React, { FunctionComponent, useState, useEffect, memo } from "react"; +import React, { FunctionComponent, memo } from "react"; import TabListButton from "./tablistbutton"; import CreateForm from "./createform"; import ImportForm from "./importform"; import { Tab } from "../types"; -import logo from "../images/logo.png"; +import logo from "../images/grouptabs-logo.svg"; import useScrollIndicator from "../hooks/scrollindicator"; import { resetMainContentScrollPosition } from "../redux/actioncreators"; @@ -22,25 +22,13 @@ interface Props { } const Tabs: FunctionComponent = (props) => { - const [hideImportForm, setHideImportForm] = useState(true); - const [isScrolled, scrollContainerRef] = useScrollIndicator(); - useEffect(() => { - if (props.visible) { - setHideImportForm(true); - } - }, [props.visible]); - const handleTabClick = (tabId: string) => { resetMainContentScrollPosition(); props.onTabClick(tabId); }; - const handleShowImportFormClick = () => { - setHideImportForm(false); - }; - return (
    @@ -64,13 +52,15 @@ const Tabs: FunctionComponent = (props) => { ) : (

    - Track shared expenses in a group of people. Every group has its - own tab like "Summer roadtrip" or "Badminton". + Track expenses in a group of people! +

    +

    + Every group has a tab like "Summer roadtrip" or "Badminton team" + – start by creating one!

    -

    Start by creating your first tab:

    )} -
    +
    = (props) => { />
    - {hideImportForm ? ( -

    - Open shared tab -

    - ) : ( - - )} +