From dbcad2b8d9dac743d2b58f07f710d64c76d2a83d Mon Sep 17 00:00:00 2001 From: Jaikiran1212 Date: Fri, 26 Jun 2026 15:31:35 +0530 Subject: [PATCH] Add icon field to Goal model and implement emoji picker in GoalManager --- package-lock.json | 3 +- package.json | 3 +- src/api/lib.ts | 2 +- src/api/types.ts | 9 +-- src/ui/features/goalmanager/GoalManager.tsx | 78 +++++++++++++++++++++ 5 files changed, 83 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index 240aecf..0800a6c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,6 @@ "@material-ui/core": "^4.12.4", "@material-ui/pickers": "^3.3.10", "@reduxjs/toolkit": "^1.5.1", - "@types/emoji-mart": "^3.0.5", "@types/node": "^17.0.41", "@types/react": "^16.9.0", "@types/react-redux": "^7.1.7", @@ -3703,6 +3702,7 @@ "resolved": "https://registry.npmjs.org/@types/emoji-mart/-/emoji-mart-3.0.9.tgz", "integrity": "sha512-qdBo/2Y8MXaJ/2spKjDZocuq79GpnOhkwMHnK2GnVFa8WYFgfA+ei6sil3aeWQPCreOKIx9ogPpR5+7MaOqYAA==", "dev": true, + "license": "MIT", "dependencies": { "@types/react": "*" } @@ -6611,6 +6611,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/emoji-mart/-/emoji-mart-3.0.1.tgz", "integrity": "sha512-sxpmMKxqLvcscu6mFn9ITHeZNkGzIvD0BSNFE/LJESPbCA8s1jM6bCDPjWbV31xHq7JXaxgpHxLB54RCbBZSlg==", + "license": "BSD-3-Clause", "dependencies": { "@babel/runtime": "^7.0.0", "prop-types": "^15.6.0" diff --git a/package.json b/package.json index 87958ce..b65e60e 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,6 @@ "@material-ui/core": "^4.12.4", "@material-ui/pickers": "^3.3.10", "@reduxjs/toolkit": "^1.5.1", - "@types/emoji-mart": "^3.0.5", "@types/node": "^17.0.41", "@types/react": "^16.9.0", "@types/react-redux": "^7.1.7", @@ -59,4 +58,4 @@ "@types/react-dom": "^18.0.5", "@types/styled-components": "^5.1.25" } -} \ No newline at end of file +} diff --git a/src/api/lib.ts b/src/api/lib.ts index 3c593ca..9af5604 100644 --- a/src/api/lib.ts +++ b/src/api/lib.ts @@ -2,7 +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:5203' export async function getUser(): Promise { try { diff --git a/src/api/types.ts b/src/api/types.ts index f75edad..86d4bb8 100644 --- a/src/api/types.ts +++ b/src/api/types.ts @@ -7,7 +7,6 @@ export interface Account { applicationId: string transactionIds: string[] } - export interface Application { id: string created: Date @@ -16,7 +15,6 @@ export interface Application { applicationStatus: ApplicationStatus userId: string } - export interface Goal { id: string name: string @@ -27,13 +25,12 @@ export interface Goal { accountId: string transactionIds: string[] tagIds: string[] + icon?: string } - export interface Tag { id: string name: string } - export interface Transaction { id: string transactionType: 'Debit' | 'Credit' | 'Transfer' @@ -43,19 +40,16 @@ export interface Transaction { description: string tagIds: string[] } - export interface User { id: string name: string email: string applicationIds: string[] } - export enum AccountType { GoalSaver, NetBankSaver, } - export enum ApplicationStatus { Received, Assigned, @@ -63,6 +57,5 @@ export enum ApplicationStatus { Approved, Rejected, } - export type ModalContent = Goal export type ModalType = 'Goal' diff --git a/src/ui/features/goalmanager/GoalManager.tsx b/src/ui/features/goalmanager/GoalManager.tsx index 0779dda..11dace5 100644 --- a/src/ui/features/goalmanager/GoalManager.tsx +++ b/src/ui/features/goalmanager/GoalManager.tsx @@ -2,6 +2,8 @@ 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 'emoji-mart/css/emoji-mart.css' +import { Picker, EmojiData } from 'emoji-mart' import 'date-fns' import React, { useEffect, useState } from 'react' import styled from 'styled-components' @@ -21,16 +23,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(undefined) + const [pickerOpen, setPickerOpen] = useState(false) 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(() => { @@ -75,10 +81,43 @@ export function GoalManager(props: Props) { } } + const onEmojiSelect = (emoji: EmojiData) => { + if ('native' in emoji) { + const selectedIcon = emoji.native + setIcon(selectedIcon) + setPickerOpen(false) + const updatedGoal: Goal = { + ...props.goal, + name: name ?? props.goal.name, + icon: selectedIcon, + } + dispatch(updateGoalRedux(updatedGoal)) + updateGoalApi(props.goal.id, updatedGoal) + } + } + return ( + + {icon && {icon}} + + setPickerOpen(!pickerOpen)}> + {icon ? 'Change Icon' : '+ Add Icon'} + + + {icon && ( + setPickerOpen(!pickerOpen)}> + Change Icon + + )} + + + + {pickerOpen && } + + @@ -182,3 +221,42 @@ const StringInput = styled.input` const Value = styled.div` margin-left: 2rem; ` + +const GoalIconContainer = styled.div` + display: flex; + flex-direction: row; + align-items: center; + margin-top: 1rem; + margin-bottom: 1rem; +` + +const GoalIcon = styled.span` + font-size: 3rem; + margin-right: 1rem; +` + +const AddIconButtonContainer = styled.div` + display: ${({ shouldShow }) => (shouldShow ? 'flex' : 'none')}; +` + +const AddIconButton = styled.button` + background: none; + border: 2px solid rgba(174, 174, 174, 1); + border-radius: 8px; + padding: 0.5rem 1rem; + font-size: 1.2rem; + cursor: pointer; + color: rgba(174, 174, 174, 1); + &:hover { + border-color: #007bff; + color: #007bff; + } +` + +const EmojiPickerContainer = styled.div` + display: ${({ isOpen }) => (isOpen ? 'flex' : 'none')}; + position: absolute; + top: ${({ hasIcon }) => (hasIcon ? '12rem' : '10rem')}; + left: 0; + z-index: 100; +`