diff --git a/src/api/lib.ts b/src/api/lib.ts index 3c593ca6..5fd39188 100644 --- a/src/api/lib.ts +++ b/src/api/lib.ts @@ -2,8 +2,7 @@ import axios from 'axios' import { user } from '../data/user' import { Goal, Transaction, User } from './types' -export const API_ROOT = 'https://fencer-commbank.azurewebsites.net' - +export const API_ROOT = 'http://localhost:11366' export async function getUser(): Promise { try { const response = await axios.get(`${API_ROOT}/api/User/${user.id}`) @@ -37,6 +36,7 @@ export async function createGoal(): Promise { userId: user.id, targetDate: new Date(), }) + return response.data } catch (error: any) { return null diff --git a/src/api/types.ts b/src/api/types.ts index f75edad0..5beff486 100644 --- a/src/api/types.ts +++ b/src/api/types.ts @@ -20,6 +20,7 @@ export interface Application { export interface Goal { id: string name: string + icon?: string targetAmount: number balance: number targetDate: Date diff --git a/src/ui/components/EmojiPicker.tsx b/src/ui/components/EmojiPicker.tsx deleted file mode 100644 index 00bb54dd..00000000 --- a/src/ui/components/EmojiPicker.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { BaseEmoji, Picker } from 'emoji-mart' -import 'emoji-mart/css/emoji-mart.css' -import { useAppSelector } from '../../store/hooks' -import { selectMode } from '../../store/themeSlice' - -type Props = { onClick: (emoji: BaseEmoji, event: React.MouseEvent) => void } - -export default function EmojiPicker(props: Props) { - const theme = useAppSelector(selectMode) - - return ( - - ) -} diff --git a/src/ui/features/goalmanager/GoalManager.tsx b/src/ui/features/goalmanager/GoalManager.tsx index 0779ddaf..973d0a18 100644 --- a/src/ui/features/goalmanager/GoalManager.tsx +++ b/src/ui/features/goalmanager/GoalManager.tsx @@ -1,5 +1,5 @@ import { faCalendarAlt } from '@fortawesome/free-regular-svg-icons' -import { faDollarSign, IconDefinition } from '@fortawesome/free-solid-svg-icons' +import { faDollarSign, IconDefinition, faSmile } from '@fortawesome/free-solid-svg-icons' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { MaterialUiPickersDate } from '@material-ui/pickers/typings/date' import 'date-fns' @@ -11,8 +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 {Picker} from 'emoji-mart' +import 'emoji-mart/css/emoji-mart.css' type Props = { goal: Goal } + export function GoalManager(props: Props) { const dispatch = useAppDispatch() @@ -21,21 +24,29 @@ export function GoalManager(props: Props) { const [name, setName] = useState(null) const [targetDate, setTargetDate] = useState(null) const [targetAmount, setTargetAmount] = useState(null) + const [icon, setIcon] = useState(props.goal.icon ?? '') + const [isPickerOpen, setIsPickerOpen] = useState(false) + // Sync state when props update 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, ]) + // Sync state when Redux store updates useEffect(() => { - setName(goal.name) - }, [goal.name]) + if (goal?.name) { + setName(goal.name) + } + }, [goal?.name]) const updateNameOnChange = (event: React.ChangeEvent) => { const nextName = event.target.value @@ -75,43 +86,85 @@ export function GoalManager(props: Props) { } } + const onEmojiSelect = (emoji: any) => { + const updatedGoal: Goal = { + ...props.goal, + icon: emoji.native, + name: name ?? props.goal.name, + targetDate: targetDate ?? props.goal.targetDate, + targetAmount: targetAmount ?? props.goal.targetAmount, + } + + setIcon(emoji.native) + dispatch(updateGoalRedux(updatedGoal)) + updateGoalApi(props.goal.id, updatedGoal) + setIsPickerOpen(false) + } + + return ( - - - - - - - - - - - - - - - - - - - - - {props.goal.balance} - - - - - - - {new Date(props.goal.created).toLocaleDateString()} - - - - ) + + + setIsPickerOpen(!isPickerOpen)} + > + {icon || } + + + {isPickerOpen && ( + + + + )} + + + + + + + + + + + + + + + + + + + + + + {props.goal.balance} + + + + + + + + {new Date(props.goal.created).toLocaleDateString()} + + + + +) } type FieldProps = { name: string; icon: IconDefinition } -type AddIconButtonContainerProps = { shouldShow: boolean } type GoalIconContainerProps = { shouldShow: boolean } type EmojiPickerContainerProps = { isOpen: boolean; hasIcon: boolean } @@ -132,6 +185,35 @@ const GoalManagerContainer = styled.div` position: relative; ` +const IconSection = styled.div` + position: relative; + margin-bottom: 1rem; +` + +const GoalIconContainer = styled.div` + font-size: 3rem; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + width: 4rem; + height: 4rem; + border-radius: 50%; + background-color: ${({ shouldShow }) => (shouldShow ? 'transparent' : 'rgba(0,0,0,0.05)')}; + + &:hover { + opacity: 0.8; + } +` + +const EmojiPickerContainer = styled.div` + position: absolute; + top: 4.5rem; + left: 0; + z-index: 10; + display: ${({ isOpen }) => (isOpen ? 'block' : 'none')}; +` + const Group = styled.div` display: flex; flex-direction: row; @@ -139,6 +221,7 @@ const Group = styled.div` margin-top: 1.25rem; margin-bottom: 1.25rem; ` + const NameInput = styled.input` display: flex; background-color: transparent; @@ -155,6 +238,7 @@ const FieldName = styled.h1` color: rgba(174, 174, 174, 1); font-weight: normal; ` + const FieldContainer = styled.div` display: flex; flex-direction: row; @@ -165,10 +249,12 @@ const FieldContainer = styled.div` color: rgba(174, 174, 174, 1); } ` + const StringValue = styled.h1` font-size: 1.8rem; font-weight: bold; ` + const StringInput = styled.input` display: flex; background-color: transparent; @@ -181,4 +267,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 e8f6d0a1..0f26f255 100644 --- a/src/ui/pages/Main/goals/GoalCard.tsx +++ b/src/ui/pages/Main/goals/GoalCard.tsx @@ -15,6 +15,8 @@ export default function GoalCard(props: Props) { const dispatch = useAppDispatch() const goal = useAppSelector(selectGoalsMap)[props.id] + + const onClick = (event: React.MouseEvent) => { event.stopPropagation() @@ -26,11 +28,18 @@ export default function GoalCard(props: Props) { const asLocaleDateString = (date: Date) => new Date(date).toLocaleDateString() return ( - - ${goal.targetAmount} - {asLocaleDateString(goal.targetDate)} - - ) + + {goal.icon && {goal.icon}} + +

{goal.name}

+ + ${goal.targetAmount} + + + {asLocaleDateString(goal.targetDate)} + +
+) } const Container = styled(Card)` @@ -54,3 +63,7 @@ const TargetDate = styled.h4` color: rgba(174, 174, 174, 1); font-size: 1rem; ` +const GoalIcon = styled.div` + font-size: 3rem; + margin-bottom: 0.5rem; +` diff --git a/src/ui/pages/Main/goals/GoalsSection.tsx b/src/ui/pages/Main/goals/GoalsSection.tsx index ab871b39..a27e501b 100644 --- a/src/ui/pages/Main/goals/GoalsSection.tsx +++ b/src/ui/pages/Main/goals/GoalsSection.tsx @@ -27,15 +27,17 @@ export default function GoalsSection() { }, [dispatch]) const onClick = async () => { - const goal = await createGoalApi() + const goal = await createGoalApi() - if (goal != null) { - dispatch(createGoalRedux(goal)) - dispatch(setContentRedux(goal)) - dispatch(setTypeRedux('Goal')) - dispatch(setIsOpenRedux(true)) - } + if (goal != null) { + dispatch(createGoalRedux(goal)) + dispatch(setContentRedux(goal)) + dispatch(setTypeRedux('Goal')) + dispatch(setIsOpenRedux(true)) } +} + + return ( @@ -74,6 +76,6 @@ const TopGroup = styled.div` } ` -const Icon = styled.a` +const Icon = styled.button` margin-left: 1rem; `