stargaze-studio/components/forms/MemberAttributes.tsx

112 lines
3.2 KiB
TypeScript
Raw Normal View History

2023-03-19 08:57:37 +00:00
import { FormControl } from 'components/FormControl'
import { AddressInput, NumberInput } from 'components/forms/FormInput'
import { useEffect, useId, useMemo } from 'react'
import { FaMinus, FaPlus } from 'react-icons/fa'
import { useInputState, useNumberInputState } from './FormInput.hooks'
export interface Attribute {
address: string
weight: number
}
export interface MemberAttributesProps {
title: string
subtitle?: string
isRequired?: boolean
attributes: [string, Attribute][]
onAdd: () => void
onChange: (key: string, attribute: Attribute) => void
onRemove: (key: string) => void
}
export function MemberAttributes(props: MemberAttributesProps) {
const { title, subtitle, isRequired, attributes, onAdd, onChange, onRemove } = props
const calculateMemberPercent = (id: string) => {
const total = attributes.reduce((acc, [, { weight }]) => acc + (weight ? weight : 0), 0)
// return attributes.map(([id, { weight }]) => [id, weight / total])
const memberWeight = attributes.find(([memberId]) => memberId === id)?.[1].weight
return memberWeight ? memberWeight / total : 0
}
2023-03-19 08:57:37 +00:00
return (
<FormControl isRequired={isRequired} subtitle={subtitle} title={title}>
{attributes.map(([id], i) => (
<MemberAttribute
key={`ma-${id}`}
defaultAttribute={attributes[i][1]}
id={id}
isLast={i === attributes.length - 1}
onAdd={onAdd}
onChange={onChange}
onRemove={onRemove}
percentage={(Number(calculateMemberPercent(id)) * 100).toFixed(2)}
2023-03-19 08:57:37 +00:00
/>
))}
</FormControl>
)
}
export interface MemberAttributeProps {
id: string
isLast: boolean
onAdd: MemberAttributesProps['onAdd']
onChange: MemberAttributesProps['onChange']
onRemove: MemberAttributesProps['onRemove']
defaultAttribute: Attribute
percentage?: string
2023-03-19 08:57:37 +00:00
}
export function MemberAttribute({
id,
isLast,
onAdd,
onChange,
onRemove,
defaultAttribute,
percentage,
}: MemberAttributeProps) {
2023-03-19 08:57:37 +00:00
const Icon = useMemo(() => (isLast ? FaPlus : FaMinus), [isLast])
const htmlId = useId()
const addressState = useInputState({
id: `ma-address-${htmlId}`,
name: `ma-address-${htmlId}`,
title: `Address`,
defaultValue: defaultAttribute.address,
})
const weightState = useNumberInputState({
id: `ma-weight-${htmlId}`,
name: `ma-weight-${htmlId}`,
title: `Weight ${percentage ? `: ${percentage}%` : ''}`,
2023-03-19 08:57:37 +00:00
defaultValue: defaultAttribute.weight,
})
useEffect(() => {
onChange(id, { address: addressState.value, weight: weightState.value })
}, [addressState.value, weightState.value, id])
return (
<div className="grid relative md:grid-cols-[50%_43%_7%] lg:grid-cols-[65%_28%_7%] 2xl:grid-cols-[70%_23%_7%] 2xl:space-x-2">
2023-03-19 08:57:37 +00:00
<AddressInput {...addressState} />
<NumberInput {...weightState} />
<div className="flex justify-end items-end pb-2 w-8">
<button
className="flex justify-center items-center p-2 bg-stargaze-80 hover:bg-plumbus-60 rounded-full"
onClick={(e) => {
e.preventDefault()
isLast ? onAdd() : onRemove(id)
}}
type="button"
>
<Icon className="w-3 h-3" />
</button>
</div>
</div>
)
}