diff --git a/cd b/cd new file mode 100644 index 0000000..e69de29 diff --git a/cmd b/cmd new file mode 100644 index 0000000..e69de29 diff --git a/dir b/dir new file mode 100644 index 0000000..e69de29 diff --git a/src/api/types.ts b/src/api/types.ts index f75edad..f6361ed 100644 --- a/src/api/types.ts +++ b/src/api/types.ts @@ -27,6 +27,7 @@ export interface Goal { accountId: string transactionIds: string[] tagIds: string[] +icon?: string } export interface Tag { diff --git a/src/ui/features/goalmanager/GoalManager.tsx b/src/ui/features/goalmanager/GoalManager.tsx index 0779dda..c1a1859 100644 --- a/src/ui/features/goalmanager/GoalManager.tsx +++ b/src/ui/features/goalmanager/GoalManager.tsx @@ -2,6 +2,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 { MaterialUiPickersDate } from '@material-ui/pickers/typings/date' +import { BaseEmoji } from 'emoji-mart' import 'date-fns' import React, { useEffect, useState } from 'react' import styled from 'styled-components' @@ -10,7 +11,10 @@ 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 GoalIcon from './GoalIcon' +import AddIconButton from './AddIconButton' type Props = { goal: Goal } export function GoalManager(props: Props) { @@ -21,16 +25,20 @@ export function GoalManager(props: Props) { const [name, setName] = useState(null) const [targetDate, setTargetDate] = useState(null) const [targetAmount, setTargetAmount] = useState(null) + const [icon, setIcon] = useState(null) + const [showEmojiPicker, setShowEmojiPicker] = useState(false) useEffect(() => { setName(props.goal.name) setTargetDate(props.goal.targetDate) setTargetAmount(props.goal.targetAmount) + setIcon(props.goal.icon ?? null) }, [ props.goal.id, props.goal.name, props.goal.targetDate, props.goal.targetAmount, + props.goal.icon, ]) useEffect(() => { @@ -75,8 +83,42 @@ export function GoalManager(props: Props) { } } + const toggleEmojiPicker = (e: React.MouseEvent) => { + e.stopPropagation() + setShowEmojiPicker(!showEmojiPicker) + } + + const onEmojiClick = (emoji: BaseEmoji, event: React.MouseEvent) => { + event.stopPropagation() + const nextIcon = emoji.native + setIcon(nextIcon) + setShowEmojiPicker(false) + const updatedGoal: Goal = { + ...props.goal, + name: name ?? props.goal.name, + targetDate: targetDate ?? props.goal.targetDate, + targetAmount: targetAmount ?? props.goal.targetAmount, + icon: nextIcon, + } + dispatch(updateGoalRedux(updatedGoal)) + updateGoalApi(props.goal.id, updatedGoal) + } + return ( + + {icon ? ( + + ) : ( + + )} + {showEmojiPicker && ( + + + + )} + + @@ -111,9 +153,6 @@ export function GoalManager(props: Props) { } type FieldProps = { name: string; icon: IconDefinition } -type AddIconButtonContainerProps = { shouldShow: boolean } -type GoalIconContainerProps = { shouldShow: boolean } -type EmojiPickerContainerProps = { isOpen: boolean; hasIcon: boolean } const Field = (props: FieldProps) => ( @@ -132,6 +171,18 @@ const GoalManagerContainer = styled.div` position: relative; ` +const IconSection = styled.div` + position: relative; + margin-bottom: 1rem; +` + +const EmojiPickerContainer = styled.div` + position: absolute; + top: 100%; + left: 0; + z-index: 100; +` + const Group = styled.div` display: flex; flex-direction: row; @@ -181,4 +232,4 @@ const StringInput = styled.input` const Value = styled.div` margin-left: 2rem; -` +` \ No newline at end of file diff --git a/src/ui/pages/Main/goals/GoalCard.tsx b/src/ui/pages/Main/goals/GoalCard.tsx index e8f6d0a..a38c6fe 100644 --- a/src/ui/pages/Main/goals/GoalCard.tsx +++ b/src/ui/pages/Main/goals/GoalCard.tsx @@ -27,6 +27,7 @@ export default function GoalCard(props: Props) { return ( + {goal.icon && {goal.icon}} ${goal.targetAmount} {asLocaleDateString(goal.targetDate)} @@ -46,6 +47,12 @@ const Container = styled(Card)` align-items: center; ` + +const Icon = styled.span` + font-size: 3rem; + margin-bottom: 0.5rem; +` + const TargetAmount = styled.h2` font-size: 2rem; ` @@ -53,4 +60,4 @@ const TargetAmount = styled.h2` const TargetDate = styled.h4` color: rgba(174, 174, 174, 1); font-size: 1rem; -` +` \ No newline at end of file