Skip to content

Commit

Permalink
😄 Benefit list item (Joystream#4644)
Browse files Browse the repository at this point in the history
* UI work

* Add logic to single input

* Disable move button on borders

* Create multiple benefit input

* Create story for multiple benefit input

* Build fix

* CR
  • Loading branch information
WRadoslaw committed Apr 22, 2024
1 parent b896125 commit e32c812
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Meta, StoryFn } from '@storybook/react'

import { BenefitInput, BenefitInputProps } from './BenefitInput'

export default {
title: 'inputs/BenefitInput',
component: BenefitInput,
} as Meta<BenefitInputProps>

const Template: StoryFn<BenefitInputProps> = (args: BenefitInputProps) => <BenefitInput {...args} />

export const Default = Template.bind({})
Default.bind({
onMoveUp: () => undefined,
onMoveDown: () => undefined,
onRemove: () => undefined,
position: 'middle',
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import styled from '@emotion/styled'

import { SvgActionTrash } from '@/assets/icons'
import { cVar, media, sizes } from '@/styles'

export const Container = styled.div`
display: grid;
grid-template-columns: 1fr 1fr;
gap: ${sizes(2)};
> *:nth-child(2) {
grid-column: 1/3;
}
> *:nth-child(3) {
grid-column: 2/3;
grid-row: 1;
justify-self: end;
}
${media.sm} {
gap: ${sizes(4)};
grid-template-columns: auto 1fr auto;
> *:nth-child(2) {
grid-column: 2/3;
}
> *:nth-child(3) {
grid-column: 3/4;
}
}
`

export const FlexBox = styled.div<{ dir?: 'column' | 'row' }>`
display: flex;
flex-direction: ${(props) => props.dir ?? 'row'};
gap: ${sizes(2)};
`
export const StyledSvgActionTrash = styled(SvgActionTrash)`
path {
fill: ${cVar('colorTextError')};
}
`

export const EmojiPlaceholder = styled.div`
width: 40px;
height: 40px;
border-radius: 50%;
background: gray;
`
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { ChangeEvent } from 'react'

import { SvgActionChevronB, SvgActionChevronT } from '@/assets/icons'
import { Button } from '@/components/_buttons/Button'
import {
Container,
EmojiPlaceholder,
FlexBox,
StyledSvgActionTrash,
} from '@/components/_inputs/BenefitInput/BenefitInput.styles'
import { Input } from '@/components/_inputs/Input'
import { TextArea } from '@/components/_inputs/TextArea'
import { useMediaMatch } from '@/hooks/useMediaMatch'

export type BenefitInputProps = {
position: 'last' | 'first' | 'middle'
onMoveUp: () => void
onMoveDown: () => void
onRemove: () => void
title?: string
description?: string
onTitleChange?: (e: ChangeEvent<HTMLInputElement>) => void
onDescriptionChange?: (e: ChangeEvent<HTMLTextAreaElement>) => void
}

export const BenefitInput = ({
onRemove,
onMoveUp,
onMoveDown,
title,
description,
onDescriptionChange,
onTitleChange,
position,
}: BenefitInputProps) => {
const smMatch = useMediaMatch('sm')
return (
<Container>
<FlexBox>
<EmojiPlaceholder />
</FlexBox>
<FlexBox dir="column">
<Input placeholder="Add benefit title" value={title} onChange={onTitleChange} />
<TextArea placeholder="Add benefit description" value={description} onChange={onDescriptionChange} />
</FlexBox>
<FlexBox dir={smMatch ? 'column' : 'row'}>
<Button variant="tertiary" icon={<SvgActionChevronT />} onClick={onMoveUp} disabled={position === 'first'} />
<Button variant="tertiary" icon={<SvgActionChevronB />} onClick={onMoveDown} disabled={position === 'last'} />
<Button variant="tertiary" icon={<StyledSvgActionTrash />} onClick={onRemove} />
</FlexBox>
</Container>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './BenefitInput'
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Meta } from '@storybook/react'
import { useForm } from 'react-hook-form'

import { BenefitsInput } from '@/components/_inputs/BenefitsInput/BenefitsInput'

export default {
title: 'inputs/BenefitsInput',
component: BenefitsInput,
} as Meta

export const Default = () => {
const { control } = useForm()

return <BenefitsInput control={control} name="storybook" />
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import styled from '@emotion/styled'
import { Control, Controller, useFieldArray } from 'react-hook-form'

import { SvgActionPlus } from '@/assets/icons'
import { Button } from '@/components/_buttons/Button'
import { BenefitInput } from '@/components/_inputs/BenefitInput'
import { sizes } from '@/styles'

type BenefitsInputProps = {
name: string
control: Control
}

export const BenefitsInput = ({ control, name }: BenefitsInputProps) => {
const { fields, move, remove, append } = useFieldArray({
control: control,
name: name,
})

return (
<Container>
{fields.map((field, index) => {
return (
<Controller
key={field.id}
name={`${name}.${index}`}
control={control}
render={({ field: { value, onChange } }) => (
<BenefitInput
onMoveUp={() => move(index, index - 1)}
onMoveDown={() => move(index, index + 1)}
onRemove={() => remove(index)}
title={value?.title}
description={value?.description}
onDescriptionChange={(e) => onChange({ ...value, description: e.target.value })}
onTitleChange={(e) => onChange({ ...value, title: e.target.value })}
position={index === 0 ? 'first' : index === fields.length - 1 ? 'last' : 'middle'}
/>
)}
/>
)
})}
<Button variant="tertiary" icon={<SvgActionPlus />} onClick={() => append({ title: '', description: '' })}>
Add benefit
</Button>
</Container>
)
}

const Container = styled.div`
display: grid;
gap: ${sizes(4)};
`
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './BenefitsInput'

0 comments on commit e32c812

Please sign in to comment.