Skip to content
Open
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
25,270 changes: 7,582 additions & 17,688 deletions package-lock.json

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
"@reduxjs/toolkit": "^1.5.1",
"@types/emoji-mart": "^3.0.5",
"@types/node": "^17.0.41",
"@types/react": "^16.9.0",
"@types/react": "^17.0.0",
"@types/react-redux": "^7.1.7",
"axios": "^0.27.2",
"axios": "^1.13.6",
"css-in-js-media": "^2.0.1",
"date-fns": "^2.28.0",
"emoji-mart": "^3.0.1",
Expand All @@ -30,10 +30,10 @@
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"start": "npx react-scripts start",
"build": "npx react-scripts build",
"test": "npx react-scripts test",
"eject": "npx react-scripts eject",
"format": "prettier --config .prettierrc 'src/**/*.ts*' --write"
},
"eslintConfig": {
Expand All @@ -56,7 +56,7 @@
},
"devDependencies": {
"@types/emoji-mart": "^3.0.9",
"@types/react-dom": "^18.0.5",
"@types/react-dom": "^17.0.0",
"@types/styled-components": "^5.1.25"
}
}
}
1 change: 1 addition & 0 deletions src/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export interface Goal {
accountId: string
transactionIds: string[]
tagIds: string[]
icon: string | null
}

export interface Tag {
Expand Down
5 changes: 4 additions & 1 deletion src/ui/features/goalmanager/AddIconButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@ export default function AddIconButton(props: Props) {
}

const Container = styled.div`
display: flex;
flex-direction: row;
align-items: flex-end;
align-items: center;
`
const Text = styled.span`
margin-left: 0.6rem;
font-size: 1.5rem;
color: rgba(174, 174, 174, 1);
text-decoration: underline;
cursor: pointer;
`
146 changes: 137 additions & 9 deletions src/ui/features/goalmanager/GoalManager.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { faCalendarAlt } from '@fortawesome/free-regular-svg-icons'
import { faDollarSign, IconDefinition } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { BaseEmoji } from 'emoji-mart'
import { MaterialUiPickersDate } from '@material-ui/pickers/typings/date'
import 'date-fns'
import React, { useEffect, useState } from 'react'
Expand All @@ -10,7 +11,11 @@ import { Goal } from '../../../api/types'
import { selectGoalsMap, updateGoal as updateGoalRedux } from '../../../store/goalsSlice'
import { useAppDispatch, useAppSelector } from '../../../store/hooks'
import DatePicker from '../../components/DatePicker'
import EmojiPicker from '../../components/EmojiPicker'
import { Theme } from '../../components/Theme'
import { media } from '../../utils/media'
import AddIconButton from './AddIconButton'
import GoalIcon from './GoalIcon'

type Props = { goal: Goal }
export function GoalManager(props: Props) {
Expand All @@ -21,21 +26,37 @@ export function GoalManager(props: Props) {
const [name, setName] = useState<string | null>(null)
const [targetDate, setTargetDate] = useState<Date | null>(null)
const [targetAmount, setTargetAmount] = useState<number | null>(null)
const [icon, setIcon] = useState<string | null>(null)
const [emojiPickerIsOpen, setEmojiPickerIsOpen] = useState(false)

useEffect(() => {
setName(props.goal.name)
setTargetDate(props.goal.targetDate)
setTargetAmount(props.goal.targetAmount)
}, [
props.goal.id,
props.goal.name,
props.goal.targetDate,
props.goal.targetAmount,
])
setIcon(props.goal.icon ?? null)
}, [props.goal.id])

useEffect(() => {
setName(goal.name)
}, [goal.name])
const hasIcon = () => icon != null

const addIconOnClick = (event: React.MouseEvent) => {
event.stopPropagation()
setEmojiPickerIsOpen(true)
}

const pickEmojiOnClick = (emoji: BaseEmoji, event: React.MouseEvent) => {
event.stopPropagation()
setIcon(emoji.native)
setEmojiPickerIsOpen(false)
const updatedGoal: Goal = {
...props.goal,
icon: emoji.native ?? props.goal.icon,
name: name ?? props.goal.name,
targetDate: targetDate ?? props.goal.targetDate,
targetAmount: targetAmount ?? props.goal.targetAmount,
}
dispatch(updateGoalRedux(updatedGoal))
updateGoalApi(props.goal.id, updatedGoal)
}

const updateNameOnChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const nextName = event.target.value
Expand Down Expand Up @@ -79,6 +100,25 @@ export function GoalManager(props: Props) {
<GoalManagerContainer>
<NameInput value={name ?? ''} onChange={updateNameOnChange} />

<IconGroup>
<IconLabel>Icon</IconLabel>
<IconControls>
<GoalIconContainer shouldShow={hasIcon()}>
<GoalIcon icon={goal.icon ?? null} onClick={addIconOnClick} />
<ChangeIconHint onClick={addIconOnClick}>Change icon</ChangeIconHint>
</GoalIconContainer>
<AddIconButton hasIcon={hasIcon()} onClick={addIconOnClick} />
</IconControls>
</IconGroup>

<EmojiPickerContainer
isOpen={emojiPickerIsOpen}
hasIcon={hasIcon()}
onClick={(event) => event.stopPropagation()}
>
<EmojiPicker onClick={pickEmojiOnClick} />
</EmojiPickerContainer>

<Group>
<Field name="Target Date" icon={faCalendarAlt} />
<Value>
Expand Down Expand Up @@ -115,6 +155,67 @@ type AddIconButtonContainerProps = { shouldShow: boolean }
type GoalIconContainerProps = { shouldShow: boolean }
type EmojiPickerContainerProps = { isOpen: boolean; hasIcon: boolean }

const IconGroup = styled.div`
display: flex;
flex-direction: column;
align-items: flex-start;
width: 100%;
margin-top: 1.25rem;
margin-bottom: 1.25rem;
gap: 0.75rem;
`

const IconLabel = styled.span`
font-size: 1.8rem;
color: rgba(174, 174, 174, 1);
font-weight: normal;
`

const IconControls = styled.div`
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
gap: 1rem;
`

const GoalIconContainer = styled.div<GoalIconContainerProps>`
display: ${(props) => (props.shouldShow ? 'flex' : 'none')};
flex-direction: column;
align-items: flex-start;
gap: 0.5rem;
`

const ChangeIconHint = styled.button`
background: none;
border: none;
padding: 0;
font-size: 1.4rem;
color: rgba(174, 174, 174, 1);
cursor: pointer;
text-decoration: underline;
font-family: inherit;

&:hover {
color: ${({ theme }: { theme: Theme }) => theme.text};
}
`

const EmojiPickerContainer = styled.div<EmojiPickerContainerProps>`
display: ${(props) => (props.isOpen ? 'flex' : 'none')};
position: absolute;
top: ${(props) => (props.hasIcon ? '10rem' : '2rem')};
left: 0;
z-index: 10;

${media('<tablet')} {
top: ${(props) => (props.hasIcon ? '8rem' : '1.5rem')};
left: 0;
right: 0;
justify-content: center;
}
`

const Field = (props: FieldProps) => (
<FieldContainer>
<FontAwesomeIcon icon={props.icon} size="2x" />
Expand All @@ -135,18 +236,35 @@ const GoalManagerContainer = styled.div`
const Group = styled.div`
display: flex;
flex-direction: row;
flex-wrap: wrap;
width: 100%;
margin-top: 1.25rem;
margin-bottom: 1.25rem;
gap: 0.5rem;

${media('<tablet')} {
flex-direction: column;
align-items: flex-start;
}
`
const NameInput = styled.input`
display: flex;
width: 100%;
max-width: 100%;
background-color: transparent;
outline: none;
border: none;
font-size: 4rem;
font-weight: bold;
color: ${({ theme }: { theme: Theme }) => theme.text};

${media('<desktop')} {
font-size: 3rem;
}

${media('<tablet')} {
font-size: 2rem;
}
`

const FieldName = styled.h1`
Expand All @@ -160,10 +278,15 @@ const FieldContainer = styled.div`
flex-direction: row;
align-items: center;
width: 20rem;
min-width: 0;

svg {
color: rgba(174, 174, 174, 1);
}

${media('<tablet')} {
width: 100%;
}
`
const StringValue = styled.h1`
font-size: 1.8rem;
Expand All @@ -181,4 +304,9 @@ const StringInput = styled.input`

const Value = styled.div`
margin-left: 2rem;

${media('<tablet')} {
margin-left: 0;
width: 100%;
}
`
17 changes: 10 additions & 7 deletions src/ui/pages/Main/Main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import React from 'react'
import styled from 'styled-components'
import Drawer from '../../surfaces/drawer/Drawer'
import Navbar from '../../surfaces/navbar/Navbar'
import { media } from '../../utils/media'
import AccountsSection from './accounts/AccountsSection'
import GoalsSection from './goals/GoalsSection'
import TransactionsSection from './transactions/TransactionsSection'
Expand Down Expand Up @@ -40,38 +39,42 @@ const MainSection = styled.div`
display: flex;
flex-direction: column;
width: calc(100% - 250px);
min-width: 0;
height: 100%;
overflow: auto;

${media('<=tablet')} {
@media (max-width: 768px) {
width: 100%;
overflow: scroll;
-webkit-overflow-scrolling: touch;
}
`

const Content = styled.div`
display: flex;
flex-direction: row;
width: 100%;
min-width: 0;
height: 100%;
justify-content: space-around;
align-items: center;

${media('<desktop')} {
@media (max-width: 600px) {
flex-direction: column;
justify-content: flex-start;
flex-wrap: none;
overflow-y: scroll;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
`

const Group = styled.div`
display: flex;
flex-direction: column;
height: 100%;
min-width: 0;
align-items: center;
justify-content: center;

${media('<=tablet')} {
@media (max-width: 600px) {
width: 100%;
justify-content: flex-start;
}
Expand Down
7 changes: 7 additions & 0 deletions src/ui/pages/Main/accounts/AccountsSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,11 @@ const TopGroup = styled.div`
const Img = styled.img`
width: 350px;
height: 209px;
max-width: 100%;
object-fit: contain;

${media('<tablet')} {
width: 100%;
height: auto;
}
`
Loading