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
4 changes: 2 additions & 2 deletions src/api/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<User | null> {
try {
const response = await axios.get(`${API_ROOT}/api/User/${user.id}`)
Expand Down Expand Up @@ -37,6 +36,7 @@ export async function createGoal(): Promise<Goal | null> {
userId: user.id,
targetDate: new Date(),
})

return response.data
} catch (error: any) {
return null
Expand Down
1 change: 1 addition & 0 deletions src/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface Application {
export interface Goal {
id: string
name: string
icon?: string
targetAmount: number
balance: number
targetDate: Date
Expand Down
20 changes: 0 additions & 20 deletions src/ui/components/EmojiPicker.tsx

This file was deleted.

160 changes: 123 additions & 37 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, 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'
Expand All @@ -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()

Expand All @@ -21,21 +24,29 @@ 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>(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<HTMLInputElement>) => {
const nextName = event.target.value
Expand Down Expand Up @@ -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 (
<GoalManagerContainer>
<NameInput value={name ?? ''} onChange={updateNameOnChange} />

<Group>
<Field name="Target Date" icon={faCalendarAlt} />
<Value>
<DatePicker value={targetDate} onChange={pickDateOnChange} />
</Value>
</Group>

<Group>
<Field name="Target Amount" icon={faDollarSign} />
<Value>
<StringInput value={targetAmount ?? ''} onChange={updateTargetAmountOnChange} />
</Value>
</Group>

<Group>
<Field name="Balance" icon={faDollarSign} />
<Value>
<StringValue>{props.goal.balance}</StringValue>
</Value>
</Group>

<Group>
<Field name="Date Created" icon={faCalendarAlt} />
<Value>
<StringValue>{new Date(props.goal.created).toLocaleDateString()}</StringValue>
</Value>
</Group>
</GoalManagerContainer>
)
<GoalManagerContainer>
<IconSection>
<GoalIconContainer
shouldShow={Boolean(icon)}
onClick={() => setIsPickerOpen(!isPickerOpen)}
>
{icon || <FontAwesomeIcon icon={faSmile} />}
</GoalIconContainer>

{isPickerOpen && (
<EmojiPickerContainer
isOpen={isPickerOpen}
hasIcon={Boolean(icon)}
>
<Picker onSelect={onEmojiSelect} />
</EmojiPickerContainer>
)}
</IconSection>

<NameInput
value={name ?? ''}
onChange={updateNameOnChange}
placeholder="Goal Name"
/>

<Group>
<Field name="Target Date" icon={faCalendarAlt} />
<Value>
<DatePicker value={targetDate} onChange={pickDateOnChange} />
</Value>
</Group>

<Group>
<Field name="Target Amount" icon={faDollarSign} />
<Value>
<StringInput
value={targetAmount ?? ''}
onChange={updateTargetAmountOnChange}
/>
</Value>
</Group>

<Group>
<Field name="Balance" icon={faDollarSign} />
<Value>
<StringValue>{props.goal.balance}</StringValue>
</Value>
</Group>

<Group>
<Field name="Date Created" icon={faCalendarAlt} />
<Value>
<StringValue>
{new Date(props.goal.created).toLocaleDateString()}
</StringValue>
</Value>
</Group>
</GoalManagerContainer>
)
}

type FieldProps = { name: string; icon: IconDefinition }
type AddIconButtonContainerProps = { shouldShow: boolean }
type GoalIconContainerProps = { shouldShow: boolean }
type EmojiPickerContainerProps = { isOpen: boolean; hasIcon: boolean }

Expand All @@ -132,13 +185,43 @@ const GoalManagerContainer = styled.div`
position: relative;
`

const IconSection = styled.div`
position: relative;
margin-bottom: 1rem;
`

const GoalIconContainer = styled.div<GoalIconContainerProps>`
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<EmojiPickerContainerProps>`
position: absolute;
top: 4.5rem;
left: 0;
z-index: 10;
display: ${({ isOpen }) => (isOpen ? 'block' : 'none')};
`

const Group = styled.div`
display: flex;
flex-direction: row;
width: 100%;
margin-top: 1.25rem;
margin-bottom: 1.25rem;
`

const NameInput = styled.input`
display: flex;
background-color: transparent;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -181,4 +267,4 @@ const StringInput = styled.input`

const Value = styled.div`
margin-left: 2rem;
`
`
23 changes: 18 additions & 5 deletions src/ui/pages/Main/goals/GoalCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -26,11 +28,18 @@ export default function GoalCard(props: Props) {
const asLocaleDateString = (date: Date) => new Date(date).toLocaleDateString()

return (
<Container key={goal.id} onClick={onClick}>
<TargetAmount>${goal.targetAmount}</TargetAmount>
<TargetDate>{asLocaleDateString(goal.targetDate)}</TargetDate>
</Container>
)
<Container onClick={onClick}>
{goal.icon && <GoalIcon>{goal.icon}</GoalIcon>}

<h2>{goal.name}</h2>

<TargetAmount>${goal.targetAmount}</TargetAmount>

<TargetDate>
{asLocaleDateString(goal.targetDate)}
</TargetDate>
</Container>
)
}

const Container = styled(Card)`
Expand All @@ -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;
`
18 changes: 10 additions & 8 deletions src/ui/pages/Main/goals/GoalsSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<Container>
Expand Down Expand Up @@ -74,6 +76,6 @@ const TopGroup = styled.div`
}
`

const Icon = styled.a`
const Icon = styled.button`
margin-left: 1rem;
`