Skip to content

Commit

Permalink
feat: quick allocation
Browse files Browse the repository at this point in the history
  • Loading branch information
malfynnction committed Apr 28, 2023
1 parent cb6371d commit b3da84f
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 9 deletions.
18 changes: 18 additions & 0 deletions cypress/e2e/dashboard.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,4 +171,22 @@ describe('Dashboard', () => {
cy.contains('Second Transaction')
cy.contains('First Transaction').should('not.exist')
})

it('can quickly allocate funds to all envelopes', () => {
cy.visit('#', { qs: { month: '2023-04' } })
cy.awaitLoading()

// set allocation
cy.get('[aria-label*="Edit Allocation for First Envelope"]').click()
cy.getInputFor('Set to amount').type('12.00')
cy.get('button[type="submit"]').click()
cy.awaitLoading()

cy.visit('#', { qs: { month: '2023-05' } })
cy.awaitLoading()
cy.contains('-12.00 Available to budget')
cy.get('select').select("Last month's allocation")
cy.clickAndWait('Submit')
cy.contains('-24.00 Available to budget')
})
})
2 changes: 1 addition & 1 deletion src/App.scss
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@
}

.error {
@apply bg-red-100 p-2 rounded-md dark:text-red-800;
@apply bg-red-100 p-2 rounded-md text-red-800 dark:text-red-600;
}

.alert {
Expand Down
29 changes: 22 additions & 7 deletions src/components/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
} from '../lib/dates'
import CategoryMonth from './CategoryMonth'
import MonthPicker from './MonthPicker'
import QuickAllocationForm from './QuickAllocationForm'

type DashboardProps = { budget: Budget }

Expand Down Expand Up @@ -59,12 +60,16 @@ const Dashboard = ({ budget }: DashboardProps) => {

const useNativeMonthPicker = isSupported.inputTypeMonth()

const loadBudgetMonth = useCallback(async () => {
const [year, month] = activeMonth.split('-')
const replaceMonthInLinks = useCallback(
(link: string) => {
const [year, month] = activeMonth.split('-')
return link.replace('YYYY', year).replace('MM', month)
},
[activeMonth]
)

return get(
budget.links.groupedMonth.replace('YYYY', year).replace('MM', month)
)
const loadBudgetMonth = useCallback(async () => {
return get(replaceMonthInLinks(budget.links.groupedMonth))
.then(data => {
setBudgetMonth(data)
if (error) {
Expand All @@ -80,6 +85,11 @@ const Dashboard = ({ budget }: DashboardProps) => {
loadBudgetMonth().then(() => setIsLoading(false))
}, [loadBudgetMonth, budget, activeMonth])

const reloadBudgetMonth = () => {
setIsLoading(true)
loadBudgetMonth().then(() => setIsLoading(false))
}

return (
<div className="dashboard">
<div className="header">
Expand Down Expand Up @@ -166,6 +176,12 @@ const Dashboard = ({ budget }: DashboardProps) => {
{t('dashboard.available')}
</div>
</div>
<div className="box text-center py-2 px-4 text-sm font-medium">
<QuickAllocationForm
link={replaceMonthInLinks(budget.links.monthAllocations)}
reloadBudgetMonth={reloadBudgetMonth}
/>
</div>

<div className="px-4 sm:px-6 lg:px-8">
<div className="mt-4 flex flex-col py-2">
Expand Down Expand Up @@ -253,8 +269,7 @@ const Dashboard = ({ budget }: DashboardProps) => {
editingEnvelope={editingEnvelope}
editEnvelope={setEditingEnvelope}
reloadBudgetMonth={() => {
setIsLoading(true)
loadBudgetMonth().then(() => setIsLoading(false))
reloadBudgetMonth()
}}
setError={setError}
/>
Expand Down
89 changes: 89 additions & 0 deletions src/components/QuickAllocationForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { QuickAllocationMode, Translation } from '../types'
import { checkStatus } from '../lib/fetch-helper'
import Alert from './Alert'
import Error from './Error'

const quickAllocationModes = [
'ALLOCATE_LAST_MONTH_BUDGET',
'ALLOCATE_LAST_MONTH_SPEND',
]

type Props = { link: string; reloadBudgetMonth: () => void }

const QuickAllocationForm = ({ link, reloadBudgetMonth }: Props) => {
const { t }: Translation = useTranslation()

const [mode, setMode] = useState<QuickAllocationMode | ''>('')
const [error, setError] = useState('')

return (
<form
onSubmit={e => {
e.preventDefault()
if (!quickAllocationModes.includes(mode)) {
console.log(mode)
return
}

fetch(link, { method: 'POST', body: JSON.stringify({ mode }) })
.then(checkStatus)
.then(() => {
setMode('')
reloadBudgetMonth()
if (error) {
setError('')
}
})
.catch(error => {
setError(error.message)
})
}}
onReset={() => {
setMode('')
}}
>
<label htmlFor="mode" className="link-blue text-base">
{t('dashboard.quickAllocation')}
</label>
<select
id="mode"
name="mode"
className="input my-2 sm:w-auto mx-auto bg-gray-100 dark:bg-slate-700"
value={mode}
onChange={e => setMode(e.target.value as QuickAllocationMode)}
>
<option value="">
{t('dashboard.quickAllocationMode.allocateBasedOn')}
</option>
{quickAllocationModes.map(quickAllocationMode => (
<option key={quickAllocationMode} value={quickAllocationMode}>
{t(`dashboard.quickAllocationMode.${quickAllocationMode}`)}
</option>
))}
</select>

<Error error={error} />

{mode === '' ? null : (
<div className="mt-5 sm:mt-6 sm:grid sm:grid-flow-row-dense sm:grid-cols-2 sm:gap-3">
<button
type="submit"
className="inline-flex w-full justify-center rounded-md border border-transparent bg-sky-500 dark:bg-sky-600 px-4 py-2 text-base font-medium text-white shadow-sm hover:bg-sky-600 dark:hover:bg-sky-500 sm:col-start-2 sm:text-sm"
>
{t('submit')}
</button>
<button
type="reset"
className="mt-3 inline-flex w-full justify-center rounded-md border border-gray-300 dark:border-gray-700 bg-white dark:bg-slate-600 px-4 py-2 text-base font-medium text-gray-700 dark:text-gray-300 shadow-sm hover:bg-gray-50 dark:hover:bg-slate-500 sm:col-start-1 sm:mt-0 sm:text-sm"
>
{t('cancel')}
</button>
</div>
)}
</form>
)
}

export default QuickAllocationForm
8 changes: 7 additions & 1 deletion src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -136,13 +136,19 @@
},
"dashboard": {
"available": "Available to budget",
"quickAllocation": "Quick Allocation",
"allocation": "Allocation",
"allocationForEnvelope": "Allocation for {{envelope}}",
"allocationForEnvelopeMonth": "Allocation for {{envelope}} ({{month}})",
"balance": "Balance",
"spent": "Spent",
"selectMonth": "Select Month",
"goToCurrentMonth": "Go to current month"
"goToCurrentMonth": "Go to current month",
"quickAllocationMode": {
"allocateBasedOn": "Allocate based on...",
"ALLOCATE_LAST_MONTH_BUDGET": "Last month's allocation",
"ALLOCATE_LAST_MONTH_SPEND": "Last month's spending"
}
},
"envelopeMonth": {
"absoluteAllocation": "Set to amount",
Expand Down
4 changes: 4 additions & 0 deletions src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,7 @@ export type FilterOptions = {
}

export type Theme = 'dark' | 'light' | 'default'

export type QuickAllocationMode =
| 'ALLOCATE_LAST_MONTH_BUDGET'
| 'ALLOCATE_LAST_MONTH_SPEND'

0 comments on commit b3da84f

Please sign in to comment.