parent
2ebe8bcd1f
commit
4a1507eba4
25 changed files with 215 additions and 58 deletions
@ -0,0 +1,5 @@ |
||||
.dank-form-item { |
||||
label { |
||||
color: white; |
||||
} |
||||
} |
@ -1,7 +1,9 @@ |
||||
import { InputNumber as AntInputNumber, InputNumberProps } from 'antd' |
||||
|
||||
import './style.scss' |
||||
|
||||
type Props = InputNumberProps |
||||
|
||||
export const InputNumber = (props: Props) => { |
||||
return <AntInputNumber {...props} /> |
||||
return <AntInputNumber className="dank-input-number" {...props} /> |
||||
} |
||||
|
@ -0,0 +1,33 @@ |
||||
.ant-input-number { |
||||
display: grid; |
||||
grid-template: 1fr / 1fr; |
||||
|
||||
div { |
||||
grid-area: 1/1/2/2; |
||||
} |
||||
|
||||
&-handler { |
||||
&-wrap { |
||||
z-index: 2; |
||||
width: 100%; |
||||
pointer-events: none; |
||||
display: flex; |
||||
flex-direction: row; |
||||
justify-content: flex-end; |
||||
align-items: center; |
||||
} |
||||
|
||||
&-up, |
||||
&-down { |
||||
pointer-events: all; |
||||
cursor: pointer; |
||||
margin: auto 0.5rem auto 0; |
||||
svg { |
||||
} |
||||
} |
||||
} |
||||
|
||||
&-input-wrap { |
||||
z-index: 1; |
||||
} |
||||
} |
@ -0,0 +1,53 @@ |
||||
import { useForm } from 'antd/lib/form/Form' |
||||
import { Button } from '../elements/Button' |
||||
import { Form } from '../elements/Form' |
||||
import { FormItem } from '../elements/FormItem' |
||||
import { Input } from '../elements/Input' |
||||
import { InputNumber } from '../elements/InputNumber' |
||||
import { |
||||
useCreateTransaction, |
||||
NewTransaction, |
||||
} from '../hooks/create/useCreateTransaction' |
||||
import { DankFormProps } from '../layout/Modal' |
||||
import { Row } from '../layout/Row' |
||||
|
||||
type Props = DankFormProps & { |
||||
stackId: string |
||||
} |
||||
|
||||
export const TransactionForm = ({ stackId, onSave, onCancel }: Props) => { |
||||
const [form] = useForm<NewTransaction>() |
||||
const create = useCreateTransaction() |
||||
|
||||
const handleFinish = async (tx: NewTransaction) => { |
||||
console.log('transaction', tx) |
||||
const res = await create(tx) |
||||
|
||||
if (!res) { |
||||
console.log("couldn't create transaction") |
||||
return |
||||
} |
||||
|
||||
onSave?.() |
||||
} |
||||
|
||||
return ( |
||||
<Form |
||||
form={form} |
||||
onFinish={handleFinish} |
||||
initialValues={{ stack: stackId }} |
||||
> |
||||
<h1>New Transaction</h1> |
||||
<FormItem label="Amount" name="amount"> |
||||
<InputNumber /> |
||||
</FormItem> |
||||
<FormItem label="Details" name="amount"> |
||||
<Input /> |
||||
</FormItem> |
||||
<Row> |
||||
<Button onClick={onCancel}>Cancel</Button> |
||||
<Button htmlType="submit">Save</Button> |
||||
</Row> |
||||
</Form> |
||||
) |
||||
} |
@ -1,9 +1,11 @@ |
||||
import { useAppContext } from '../../contexts/AppContext' |
||||
import { Transaction } from '../../types' |
||||
|
||||
export type NewTransaction = Omit<Transaction, 'id'> |
||||
|
||||
export const useCreateTransaction = () => { |
||||
const api = useAppContext() |
||||
|
||||
return (body: Omit<Transaction, 'id'>): Promise<Transaction> => |
||||
api.post<Transaction>('/transactions', body) |
||||
return (body: NewTransaction): Promise<Transaction | null> => |
||||
api.post<Transaction>('/transactions/', body) |
||||
} |
||||
|
@ -1,4 +1,5 @@ |
||||
import { Transaction } from '../../types' |
||||
import { useGet } from '../util/useGet' |
||||
|
||||
export const useTransactions = () => useGet<Transaction[]>(`/transactions/`) |
||||
export const useTransactions = () => |
||||
useGet<Transaction[]>(`/transactions/`, { mode: 'list' }) |
||||
|
@ -1,9 +1,16 @@ |
||||
import { ModalProps } from 'antd' |
||||
import { ReactNode } from 'react' |
||||
import { ReactElement, cloneElement } from 'react' |
||||
import './style.scss' |
||||
|
||||
type Props = ModalProps & { children: ReactNode } |
||||
type Props = ModalProps & { children: ReactElement } |
||||
|
||||
export const Modal = ({ children, ...props }: Props) => { |
||||
return <div className="dank-modal">{children}</div> |
||||
export type DankFormProps = { |
||||
onSave?: () => void |
||||
onCancel?: () => void |
||||
} |
||||
|
||||
export const Modal = ({ children, visible }: Props) => { |
||||
const el = cloneElement(children, (props: DankFormProps) => ({ ...props })) |
||||
|
||||
return visible ? <div className="dank-modal">{el}</div> : null |
||||
} |
||||
|
@ -0,0 +1,10 @@ |
||||
import React from 'react' |
||||
import './style.scss' |
||||
|
||||
type Props = { |
||||
children: React.ReactNode |
||||
} |
||||
|
||||
export const Row = ({ children }: Props) => { |
||||
return <div className="dank-row">{children}</div> |
||||
} |
@ -0,0 +1,6 @@ |
||||
.dank-row { |
||||
display: flex; |
||||
flex-direction: row; |
||||
justify-content: space-between; |
||||
margin: 1rem 0; |
||||
} |
@ -1,40 +1,47 @@ |
||||
import { Stack } from '../../types' |
||||
import './style.scss' |
||||
import _ from 'lodash' |
||||
import { useState } from 'react' |
||||
import { Modal } from '../../layout/Modal' |
||||
import { TransactionForm } from '../../forms/TransactionForm' |
||||
|
||||
type Props = { |
||||
stack: Stack |
||||
} |
||||
|
||||
export const FundBar = ({ stack }: Props) => { |
||||
const amount = _.sumBy(stack.transactions, 'amount') |
||||
console.log('amount', stack.id, amount) |
||||
const max = stack.amount |
||||
const amount = _.sumBy(stack.transactions, (tx) => parseFloat(tx.amount)) |
||||
const max = parseFloat(stack.amount) |
||||
const current = max - amount |
||||
const percent = Math.max(current / max, 0) |
||||
const hue = percent * 120 |
||||
const u = Math.max(current / max, 0) |
||||
|
||||
const [newTx, setNewTx] = useState(false) |
||||
|
||||
const addTransaction = () => { |
||||
console.log(`adding transaction to => ${stack.name}`) |
||||
setNewTx(true) |
||||
} |
||||
|
||||
return ( |
||||
<div className="fundbar"> |
||||
<div |
||||
className={`back`} |
||||
onClick={() => console.log(`adding transaction to => ${stack.name}`)} |
||||
></div> |
||||
<div |
||||
className={`front`} |
||||
style={{ |
||||
background: `hsl(${hue}, 100%, 50%)`, |
||||
height: `${percent * 40 + 10}vmin`, |
||||
}} |
||||
> |
||||
<h3>{stack.name}</h3> |
||||
</div> |
||||
<div |
||||
className={`totals`} |
||||
style={{ color: `hsl(0, 0%, ${Math.abs(1 - percent) * 100}%)` }} |
||||
> |
||||
${Math.floor(current)} / ${max} |
||||
<> |
||||
<div className="fundbar"> |
||||
<div className="back" onClick={addTransaction}> |
||||
<h3>{stack.name}</h3> |
||||
</div> |
||||
<div |
||||
className="front" |
||||
style={{ |
||||
background: `hsl(${u * 120}, 100%, 50%)`, |
||||
height: `${u * 100}%`, |
||||
}} |
||||
></div> |
||||
<div className="totals"> |
||||
${Math.floor(current)} / ${max} |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<Modal visible={newTx} onCancel={() => setNewTx(false)}> |
||||
<TransactionForm stackId={stack.id} /> |
||||
</Modal> |
||||
</> |
||||
) |
||||
} |
||||
|
Loading…
Reference in new issue