Skip to content

Commit

Permalink
Improved CPF code support and tx ux
Browse files Browse the repository at this point in the history
  • Loading branch information
ystxn committed Apr 13, 2024
1 parent cdd363b commit 20a73d3
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 15 deletions.
1 change: 0 additions & 1 deletion src/core/api.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ const api = () => {
bulkEditTransactions: (payload, callback) => apiCall(PUT, 'transaction/bulk', callback, payload),
deleteTransaction: (id, callback) => apiCall(DELETE, `transaction/${id}`, callback),
suggestRemarks: (input, callback) => apiCall(GET, `suggest/remarks?q=${clean(input)}`, callback),
suggestCode: (input, callback) => apiCall(GET, `suggest/code?q=${clean(input)}`, callback),
suggestCompany: (input, callback) => apiCall(GET, `suggest/company?q=${clean(input)}`, callback),
getCategories: (callback) => apiCall(GET, 'suggest/categories', callback),
listTemplates: (callback) => apiCall(GET, 'template', callback),
Expand Down
2 changes: 1 addition & 1 deletion src/settings/cpf-slider.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const CpfSlider = ({ cpfRatio, setCpfRatio, cpfAllocationInvalid }) => {
(parseFloat(cpfRatio.ordinaryRatio) + parseFloat(cpfRatio.specialRatio))
];

const updateCpfSlider = (event, newValue) => setCpfRatio({
const updateCpfSlider = (_, newValue) => setCpfRatio({
ordinaryRatio: newValue[0],
specialRatio: parseFloat((newValue[1] - newValue[0]).toFixed(4)),
medisaveRatio: parseFloat((1 - newValue[1]).toFixed(4)),
Expand Down
36 changes: 25 additions & 11 deletions src/transactions/add-transaction-dialog.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'dayjs/locale/en-sg';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { cpfCodes } from '../util/cpf-codes';
import { createFilterOptions } from '@mui/material/Autocomplete';
import { DatePicker } from '@mui/x-date-pickers/DatePicker';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
Expand Down Expand Up @@ -60,7 +61,7 @@ const AddTransactionDialog = ({
const setVisibleTransactionId = state.useState(state.visibleTransactionId)[1];
const {
listAccounts, addTransaction, editTransaction, listTransactions,
showStatus, suggestRemarks, suggestCode, suggestCompany, getCategories,
showStatus, suggestRemarks, suggestCompany, getCategories,
} = api();

useEffect(() => {
Expand Down Expand Up @@ -100,6 +101,8 @@ const AddTransactionDialog = ({
} else {
setMonth(date.startOf('month'));
}
} else if (selectedAccount?.type === 'Retirement') {
setMonth(date.subtract(1, 'month').startOf('month'));
}
}, [ date ]);

Expand All @@ -125,6 +128,9 @@ const AddTransactionDialog = ({
if (tx.originalAmount) {
tx.originalAmount *= side;
}
if (tx.code && tx.code.indexOf(':') > -1) {
tx.code = tx.code.split(':').shift();
}
tx['@type'] = (selectedAccount?.multiCurrency ? 'fx-' : '') + selectedAccount?.type.toLowerCase();
if (selectedAccount?.type === 'Credit') {
tx.billingMonth = month.toISOString();
Expand Down Expand Up @@ -356,7 +362,7 @@ const AddTransactionDialog = ({
options={categories}
filterOptions={createFilterOptions({ limit: 5 })}
value={category}
onChange={(e, v) => setCategory(v)}
onChange={(_, v) => setCategory(v)}
renderInput={(params) => (
<TextField
required
Expand All @@ -369,17 +375,24 @@ const AddTransactionDialog = ({
/>
),
code: (
<AutoFill
<Autocomplete
key="code"
promise={suggestCode}
freeSolo
autoComplete
options={cpfCodes.map((c) => c.code)}
filterOptions={createFilterOptions({ limit: 5 })}
getOptionLabel={(o) => cpfCodes.find(({ code }) => code === o) ? (o + ': ' + cpfCodes.find(({ code }) => code === o).description) : o}
renderInput={(params) => (
<TextField
required
inputProps={{ minLength: 3, maxLength: 3 }}
name="code"
label="Code"
{...params}
/>
)}
value={code}
onChange={(e, v) => setCode(v.toUpperCase())}
fieldProps={{
required: true,
inputProps: { minLength: 2 },
name: 'code',
label: 'Code'
}}
onChange={(_, v) => setCode(v?.toUpperCase() || '')}
/>
),
company: (
Expand All @@ -391,6 +404,7 @@ const AddTransactionDialog = ({
name: 'company',
label: 'Company'
}}
sx={{ display: (code === 'CON') ? 'flex' : 'none' }}
/>
),
ordinaryAmount: (
Expand Down
2 changes: 1 addition & 1 deletion src/transactions/auto-fill.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const AutoFill = ({ initValue, fieldProps, promise, ...props }) => {
promise(request, callback), 200), []);

useEffect(() => {
if (inputValue.length < 3) {
if (inputValue.length < 1) {
return;
}
setOptions([]);
Expand Down
9 changes: 8 additions & 1 deletion src/transactions/transactions-grid.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
import {
formatNumber, formatDecimal, formatDecimalHideZero, formatDecimalAbs, formatDate, formatMonth,
} from '../util/formatters';
import { cpfCodes } from '../util/cpf-codes';
import { GridPagination } from '@mui/x-data-grid';
import { HorizontalLoader } from '../core/loader';
import { pink, lightGreen } from '@mui/material/colors';
Expand All @@ -19,6 +20,7 @@ import api from '../core/api';
import Box from '@mui/system/Box';
import state from '../core/state';
import styled from 'styled-components';
import Tooltip from '@mui/material/Tooltip';
import useMediaQuery from '@mui/material/useMediaQuery';

const GridBox = styled.div`
Expand Down Expand Up @@ -102,6 +104,11 @@ const TransactionsGrid = ({ accounts, setShowAddDialog, setTransactionToEdit, ap

const getColourClassForValue = ({ value }) => !value ? '' : value > 0 ? 'green' : 'red';

const CpfCode = ({ value }) => {
const title = cpfCodes.find((c) => c.code === value)?.description || 'No description available';
return <Tooltip title={title}><span>{value}</span></Tooltip>;
};

const columns = {
account: { flex : 2, field: 'accountId', headerName: 'Account', valueGetter: getAccountName },
date: { flex: 2.5, field: 'date', headerName: 'Date', type: 'date', valueFormatter: formatDate },
Expand All @@ -115,7 +122,7 @@ const TransactionsGrid = ({ accounts, setShowAddDialog, setTransactionToEdit, ap
balance: { flex: 2, field: 'balance', headerName: 'Balance', type: 'number', valueFormatter: formatDecimal },
remarks: { flex: 4, field: 'remarks', headerName: 'Remarks' },
category: { flex: 2, field: 'category', headerName: 'Category' },
code: { flex: 2, field: 'code', headerName: 'Code' },
code: { flex: 2, field: 'code', headerName: 'Code', renderCell: CpfCode },
company: { flex: 2, field: 'company', headerName: 'Company' },
ordinaryAmount: { flex: 2, field: 'ordinaryAmount', headerName: 'Ordinary', type: 'number', valueFormatter: formatDecimal, cellClassName: getColourClassForValue },
specialAmount: { flex: 2, field: 'specialAmount', headerName: 'Special', type: 'number', valueFormatter: formatDecimal, cellClassName: getColourClassForValue },
Expand Down
39 changes: 39 additions & 0 deletions src/util/cpf-codes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
export const cpfCodes = [
{ code: 'CON', description: 'Contributions' },
{ code: 'HSE', description: 'HDB flats and other residential properties' },
{ code: 'PMI', description: 'Private Medical Insurance' },
{ code: 'DPS', description: 'Dependants\' Protection Scheme' },
{ code: 'CSL', description: 'CareShield Life' },
{ code: 'ADJ', description: 'Adjustment / Interest on recovered CPF contributions' },
{ code: 'AMP', description: 'Additional Monthly Payout' },
{ code: 'BAL', description: 'Balance' },
{ code: 'CLA', description: 'CPF LIFE Annuity Premium' },
{ code: 'CLB', description: 'CPF LIFE Bonus (L-Bonus)' },
{ code: 'CLC', description: 'CPF LIFE Change of plan' },
{ code: 'CLI', description: 'CPF LIFE Payout' },
{ code: 'CLR', description: 'Refund from CPF LIFE' },
{ code: 'CLS', description: 'CPF LIFE Switch of plan' },
{ code: 'DPC', description: 'Dependants\' Protection Scheme return of premium refund' },
{ code: 'DPR', description: 'Dependants\' Protection Scheme premium refund' },
{ code: 'DPP', description: 'DPS Fund privatisation residual distribution' },
{ code: 'DVB', description: 'Deferment and/or Voluntary Deferment Bonus' },
{ code: 'EDN', description: 'Education Scheme' },
{ code: 'ESH', description: 'ElderShield' },
{ code: 'HPR', description: 'Home Protection Scheme Rebate' },
{ code: 'HPS', description: 'Home Protection Scheme' },
{ code: 'HRF', description: 'Withdrawal from balance of housing refund' },
{ code: 'INT', description: 'Interest for the whole year' },
{ code: 'INV', description: 'CPF Investment Scheme' },
{ code: 'MED', description: 'Medisave' },
{ code: 'MSH', description: 'MediShield' },
{ code: 'MSL', description: 'MediShield Life' },
{ code: 'MGS', description: 'Medical Grounds Scheme' },
{ code: 'PTY', description: 'Non-residential property' },
{ code: 'RFD', description: 'Refund of overpaid contributions' },
{ code: 'RSS', description: 'Retirement Sum Scheme' },
{ code: 'RST', description: 'Top-ups under CPF Retirement Sum Topping-Up Scheme' },
{ code: 'SNS', description: 'Special Needs Savings Scheme' },
{ code: 'SE:', description:'Payment by self-employed person' },
{ code: 'TFR', description: 'Transfer between accounts' },
{ code: 'WDL', description: 'Withdrawal of CPF savings' },
];

0 comments on commit 20a73d3

Please sign in to comment.