Skip to content

feat: SB-2466 - feedback component#6

Open
jfeldstatnett wants to merge 11 commits into
mainfrom
SB-2466
Open

feat: SB-2466 - feedback component#6
jfeldstatnett wants to merge 11 commits into
mainfrom
SB-2466

Conversation

@jfeldstatnett
Copy link
Copy Markdown

📝 Description

Add new Feedback component.

Users can rate, comment and submit their feedback anonymously.

Main goal of the component is the keep the bar as low as possible for users to go through with submitting their feedback. The fewer hoops they have to through, the lower risk they will give up before submitting.

🔄 Type of Change

  • ✨ New feature (non-breaking change which adds functionality)

✅ Checklist

  • I have performed a self-review of my code
  • I have added relevant tests
  • I have added docs to ds-www (if applicable)
  • I have written and generated CHANGELOG.md (if applicable)
  • I have updated dependencies and verified no new breaking changes (if applicable)

📸 Screenshots (if applicable)

image image

@jfeldstatnett jfeldstatnett requested a review from ssandoy April 24, 2026 06:55
@jfeldstatnett jfeldstatnett requested a review from a team as a code owner April 24, 2026 06:55
Copy link
Copy Markdown

@ssandoy ssandoy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Mostly nits from me

Comment thread ds-components/src/components/feedback/Feedback.tsx Outdated
Comment thread ds-components/src/components/feedback/Feedback.tsx Outdated
Comment thread ds-components/src/components/feedback/Feedback.tsx Outdated
Comment thread ds-components/src/components/feedback/FeedbackCollectingButtonGroup.tsx Outdated
Comment thread ds-components/src/components/feedback/FeedbackIdle.tsx Outdated
Comment thread ds-css/src/components/feedback.css Outdated
Copy link
Copy Markdown
Member

@poengen poengen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall a good structure with the compound component pattern. I think there's some confusion with the state handling and possibly room for some cleanup.

Proposed change: Remove the variant-prop on the Feedback component.

size,
className,
children,
onClick,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This onClick prop should be used to set which child component is active. Either idle, collecting or submitted.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was technically not required, but it does make it easier to read, so this has now been changed.

Copy link
Copy Markdown
Member

@poengen poengen May 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code runs without it, but its a good practice to use it

label: 'Feedback',
description: 'Form for submitting feedback',
el: (
<Feedback>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you don't make use of the variant-prop. But this example seems to work also.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variant as a prop has been removed. Variant in other places has been renamed for clarity. For example as selectedFeedbackType to make it more obvious what this variant actually is.

<Feedback.Idle>
<Heading size='small'>How was this page to use?</Heading>
<Feedback.Idle.ButtonGroup aria-label='Rate this page'>
<Feedback.Idle.Button size='large' variant='happy'>Good</Feedback.Idle.Button>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should use an arrow function here in the onClick prop to set active state

})

const Component = () => {
const [state, setState] = useState<ActiveState>('idle')
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename to active state or something more descriptive. Just "state" is difficult to understand what means.

import { BodyText, Button, Feedback, Heading, Loader, Textarea, VerticalSpace } from '@elhub/ds-components'
import { IconCheckCircle } from '@elhub/ds-icons'

type ActiveState = 'idle' | 'collecting' | 'submitting' | 'submitted' | 'error'
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Submitting is not an activeState IMO. Is is a pending state between collecting and submitted, and for that it is better to use the isPending param you get from a fetching library like tanstack query. Not necessary to have an internal "submitting" state.

const { error: { hasError } = {}, size: formItemSize } = useFormItemContext()
const [internalVariant, setInternalVariant] = useState<FeedbackVariant | undefined>(defaultVariant)

const isParentControlled = variant !== undefined
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand the purpose of this prop. You have one example using it while another example not using it.

onClick,
...rest
}) => {
const { size: contextSize, variant: contextVariant, onVariantChange } = useFeedbackContext()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why the context is needed. I dont think size should be in the context here, since it can and probably should be controlled directly from the consumer app if needed.

The variant prop I'm asking about elsewhere.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a context can be argued for here due to the complexity of the component. The size is still controlled from the consumer size by passing the prop (as it should be)


const Component = () => {
const [state, setState] = useState<ActiveState>('idle')
const [variant, setVariant] = useState<FeedbackVariant | null>(null)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have a variant prop here but its not being used to set the Feedback.Idle.Button variant prop?

But they have the same enum type with "happy", "neutral" and "sad". This is confusing.

type ActiveState = 'idle' | 'collecting' | 'submitting' | 'submitted' | 'error'
type FeedbackVariant = 'happy' | 'neutral' | 'sad'

const wait = (ms: number): Promise<void> =>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont think this function belongs here.

const submit = async () => {
if (!variant) return
setState('submitting')
await wait(900)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wait functions are a big no-no

}

const FeedbackFlow: React.FC<FeedbackFlowProps> = ({ title, description, simulateBackendError = false }) => {
const [feedbackState, setFeedbackState] = useState<ActiveState>('idle')
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use activeState and setActiveState here. More descriptive, and the type is ActiveState

aria-checked={selected}
className={buttonClass}
onClick={(event) => {
onFeedbackTypeChange?.(variant)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FeedbackType or Variant? Be consistent and descriptive

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants