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
21,002 changes: 3,033 additions & 17,969 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"private": true,
"dependencies": {
"@date-io/date-fns": "^1.3.13",
"@fortawesome/fontawesome-svg-core": "^6.7.2",
"@fortawesome/free-regular-svg-icons": "^6.1.1",
"@fortawesome/free-solid-svg-icons": "^6.1.1",
"@fortawesome/react-fontawesome": "^0.1.18",
Expand Down Expand Up @@ -59,4 +60,4 @@
"@types/react-dom": "^18.0.5",
"@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
3 changes: 2 additions & 1 deletion src/ui/components/EmojiPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { BaseEmoji, Picker } from 'emoji-mart'
import 'emoji-mart/css/emoji-mart.css'
import { useAppSelector } from '../../store/hooks'
import { selectMode } from '../../store/themeSlice'
import type { MouseEvent } from 'react'

type Props = { onClick: (emoji: BaseEmoji, event: React.MouseEvent) => void }
type Props = { onClick: (emoji: BaseEmoji, event: MouseEvent) => void }

export default function EmojiPicker(props: Props) {
const theme = useAppSelector(selectMode)
Expand Down
3 changes: 2 additions & 1 deletion src/ui/features/goalmanager/AddIconButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'date-fns'
import React from 'react'
import styled from 'styled-components'
import { TransparentButton } from '../../components/TransparentButton'
import type { IconProp } from '@fortawesome/fontawesome-svg-core';

type Props = { hasIcon: boolean; onClick: (event: React.MouseEvent) => void }

Expand All @@ -13,7 +14,7 @@ export default function AddIconButton(props: Props) {
return (
<Container>
<TransparentButton onClick={props.onClick}>
<FontAwesomeIcon icon={faSmile} size="2x" />
<FontAwesomeIcon icon={faSmile as IconProp} size="2x" />
<Text>Add icon</Text>
</TransparentButton>
</Container>
Expand Down
80 changes: 78 additions & 2 deletions src/ui/features/goalmanager/GoalManager.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { faCalendarAlt } from '@fortawesome/free-regular-svg-icons'
import { faDollarSign, IconDefinition } from '@fortawesome/free-solid-svg-icons'
import { faDollarSign, faSmile, IconDefinition } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { MaterialUiPickersDate } from '@material-ui/pickers/typings/date'
import 'date-fns'
Expand All @@ -11,6 +11,11 @@ import { selectGoalsMap, updateGoal as updateGoalRedux } from '../../../store/go
import { useAppDispatch, useAppSelector } from '../../../store/hooks'
import DatePicker from '../../components/DatePicker'
import { Theme } from '../../components/Theme'
import { BaseEmoji } from 'emoji-mart'
import EmojiPicker from '../../components/EmojiPicker'
import { TransparentButton } from '../../components/TransparentButton'
import type { IconProp } from '@fortawesome/fontawesome-svg-core';
import GoalIcon from './GoalIcon'

type Props = { goal: Goal }
export function GoalManager(props: Props) {
Expand All @@ -21,16 +26,28 @@ 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)
const hasIcon = () => icon != null

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


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

useEffect(() => {
Expand Down Expand Up @@ -75,6 +92,24 @@ export function GoalManager(props: Props) {
}
}

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)
}

return (
<GoalManagerContainer>
<NameInput value={name ?? ''} onChange={updateNameOnChange} />
Expand Down Expand Up @@ -106,6 +141,26 @@ export function GoalManager(props: Props) {
<StringValue>{new Date(props.goal.created).toLocaleDateString()}</StringValue>
</Value>
</Group>

<AddIconButtonContainer shouldShow={hasIcon()}>
<TransparentButton onClick={addIconOnClick}>
<FontAwesomeIcon icon={faSmile as IconProp} size="2x" />
<AddIconButtonText>Add icon</AddIconButtonText>
</TransparentButton>
</AddIconButtonContainer>

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

<GoalIconContainer shouldShow={hasIcon()}>
<GoalIcon icon={goal.icon} onClick={addIconOnClick} />
</GoalIconContainer>
</GoalManagerContainer>
)
}
Expand All @@ -117,7 +172,7 @@ type EmojiPickerContainerProps = { isOpen: boolean; hasIcon: boolean }

const Field = (props: FieldProps) => (
<FieldContainer>
<FontAwesomeIcon icon={props.icon} size="2x" />
<FontAwesomeIcon icon={props.icon as IconProp} size="2x" />
<FieldName>{props.name}</FieldName>
</FieldContainer>
)
Expand Down Expand Up @@ -182,3 +237,24 @@ const StringInput = styled.input`
const Value = styled.div`
margin-left: 2rem;
`

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

const GoalIconContainer = styled.div<GoalIconContainerProps>`
display: ${(props) => (props.shouldShow ? 'flex' : 'none')};
`

const AddIconButtonContainer = styled.div<AddIconButtonContainerProps>`
display: ${(props) => (props.shouldShow ? 'flex' : 'none')};
`

const AddIconButtonText = styled.span`
margin-left: 0.75rem;
font-size: 1.6rem;
color: #007bff;
`
3 changes: 2 additions & 1 deletion src/ui/features/themeswitcher/ThemeSwitcher.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
setDarkMode as setDarkModeRedux,
setLightMode as setLightModeRedux,
} from '../../../store/themeSlice'
import type { IconProp } from '@fortawesome/fontawesome-svg-core';

export default function ThemeSwitcher() {
const mode = useAppSelector(selectMode)
Expand All @@ -19,7 +20,7 @@ export default function ThemeSwitcher() {

return (
<div onClick={onClick}>
<FontAwesomeIcon icon={mode === 'light' ? faMoon : faSun} size="2x" />
<FontAwesomeIcon icon={(mode === 'light' ? faMoon : faSun) as IconProp} size="2x" />
</div>
)
}
3 changes: 3 additions & 0 deletions src/ui/pages/Main/goals/GoalCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export default function GoalCard(props: Props) {
<Container key={goal.id} onClick={onClick}>
<TargetAmount>${goal.targetAmount}</TargetAmount>
<TargetDate>{asLocaleDateString(goal.targetDate)}</TargetDate>
<Icon>{goal.icon}</Icon>
</Container>
)
}
Expand All @@ -54,3 +55,5 @@ const TargetDate = styled.h4`
color: rgba(174, 174, 174, 1);
font-size: 1rem;
`

const Icon = styled.h1`font-size: 5.5rem;`
3 changes: 2 additions & 1 deletion src/ui/pages/Main/goals/GoalsSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import { SectionHeading } from '../../../components/SectionHeading'
import { media } from '../../../utils/media'
import GoalsContent from './GoalsContent'
import type { IconProp } from '@fortawesome/fontawesome-svg-core';

export default function GoalsSection() {
const dispatch = useAppDispatch()
Expand Down Expand Up @@ -42,7 +43,7 @@ export default function GoalsSection() {
<TopGroup>
<SectionHeading>Goals</SectionHeading>
<Icon onClick={onClick}>
<FontAwesomeIcon icon={faPlusCircle} size="2x" className="alert" />
<FontAwesomeIcon icon={faPlusCircle as IconProp} size="2x" className="alert" />
</Icon>
</TopGroup>

Expand Down
2 changes: 1 addition & 1 deletion src/ui/pages/Main/transactions/TransactionsContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default function TransactionsContent(props: Props) {
return (
<>
{props.transactions.sort(sortByDateDesc).map((transaction) => (
<TransactionItem transaction={transaction} />
<TransactionItem key={transaction.id} transaction={transaction} />
))}
</>
)
Expand Down
7 changes: 4 additions & 3 deletions src/ui/surfaces/drawer/Drawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import React from 'react'
import styled from 'styled-components'
import CommBank from '../../../assets/images/commbank.svg'
import { media } from '../../utils/media'
import type { IconProp } from '@fortawesome/fontawesome-svg-core';

export default function Navbar() {
return (
Expand All @@ -14,19 +15,19 @@ export default function Navbar() {
</LogoWrapper>

<DrawerItem isSelected={true}>
<FontAwesomeIcon icon={faRocket} size="2x" />
<FontAwesomeIcon icon={faRocket as IconProp} size="2x" />
<span>Dashboard</span>
</DrawerItem>

<DrawerItem isSelected={false}>
<FontAwesomeIcon icon={faChartLine} size="2x" />
<FontAwesomeIcon icon={faChartLine as IconProp} size="2x" />
<span>Goals</span>
</DrawerItem>
</Section>

<Section>
<DrawerItem isSelected={false}>
<FontAwesomeIcon icon={faGear} size="2x" />
<FontAwesomeIcon icon={faGear as IconProp} size="2x" />
<span>Settings</span>
</DrawerItem>
</Section>
Expand Down
5 changes: 3 additions & 2 deletions src/ui/surfaces/navbar/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useAppSelector } from '../../../store/hooks'
import { selectUser } from '../../../store/userSlice'
import ThemeSwitcher from '../../features/themeswitcher/ThemeSwitcher'
import { media } from '../../utils/media'
import type { IconProp } from '@fortawesome/fontawesome-svg-core';

export default function Navbar() {
const user = useAppSelector(selectUser)
Expand All @@ -19,11 +20,11 @@ export default function Navbar() {
</NavbarAction>

<NavbarAction>
<FontAwesomeIcon icon={faEnvelope} size="2x" />
<FontAwesomeIcon icon={faEnvelope as IconProp} size="2x" />
</NavbarAction>

<NavbarAction>
<FontAwesomeIcon icon={faBell} size="2x" />
<FontAwesomeIcon icon={faBell as IconProp} size="2x" />
</NavbarAction>

<UserGroup>
Expand Down