Skip to content

Commit

Permalink
feat: add additional options to the nps component (#405)
Browse files Browse the repository at this point in the history
* feat: add additional options to the nps component

* update css

* add heuristic for jumpiness

* changeset
  • Loading branch information
christianmat authored Dec 16, 2024
1 parent 68564f1 commit 991ebe2
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 14 deletions.
5 changes: 5 additions & 0 deletions .changeset/eighty-laws-exercise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@frigade/react": patch
---

Adds the ability to override the default scoring (options) on the `Survey.NPS` component
12 changes: 10 additions & 2 deletions apps/smithy/src/stories/Survey/Survey.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,21 @@ export default {

export const NPS = {
args: {
flowId: "flow_SJjL59eSt9A112vJ",
dismissible: true,
options: [
{ label: "😞", value: "0" },
{ label: "😕", value: "1" },
{ label: "😐", value: "2" },
{ label: "🙂", value: "3" },
{ label: "😍", value: "4" },
],
},
decorators: [
(_: StoryFn, options: StoryContext) => {
return (
<Box fontFamily="Arial">
<Box backgroundColor="blue" height="500px">
<Box height="500px">
Other elements on the page
<Button.Primary
onClick={() => {
Expand All @@ -24,7 +32,7 @@ export const NPS = {
Change url
</Button.Primary>
<Survey.NPS
flowId="flow_SJjL59eSt9A112vJ"
flowId={options.args.flowId as string}
alignSelf="flex-end"
justifySelf="flex-end"
{...options.args}
Expand Down
68 changes: 64 additions & 4 deletions packages/react/src/components/Survey/NPS.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,63 @@ import { Form, type FormProps } from '@/components/Form'
import { NPSField } from './NPSField'
import { useFlow } from '@/hooks/useFlow'

export function NPS({ as = Dialog, flowId, fieldTypes, part, ...props }: FormProps) {
type NPSOptions = { label: string; value: string }[]

interface NPSProps extends FormProps {
/**
* The options to display in the NPS field.
* If not provided, the default NPS numbers from 0 to 10 will be used.
*/
options?: NPSOptions

/**
* The label to display for the positive end of the NPS scale.
* If not provided, the default label "Extremely likely" will be used.
*/
positiveLabel?: string

/**
* The label to display for the negative end of the NPS scale.
* If not provided, the default label "Not likely at all" will be used.
*/
negativeLabel?: string
}

export function NPS({
as = Dialog,
flowId,
fieldTypes,
part,
options,
positiveLabel,
negativeLabel,
...props
}: NPSProps) {
const { flow } = useFlow(flowId)

const defaultOptions =
(flow?.props?.options as NPSOptions) ??
[...Array(11)].map((_, i) => ({ label: `${i}`, value: `${i}` }))
const npsOptions = options || defaultOptions

return (
<Form
alignSelf="end"
as={as}
flowId={flowId}
fieldTypes={{
nps: NPSField,
nps: (fieldProps) => (
<NPSField
{...fieldProps}
options={npsOptions}
positiveLabel={
(flow?.props?.positiveLabel as string) ?? positiveLabel ?? 'Extremely likely'
}
negativeLabel={
(flow?.props?.negativeLabel as string) ?? negativeLabel ?? 'Not likely at all'
}
/>
),
...fieldTypes,
}}
modal={false}
Expand All @@ -33,11 +80,21 @@ export function NPS({ as = Dialog, flowId, fieldTypes, part, ...props }: FormPro
// Hides the submit button on the first page
...(!flow || flow.getCurrentStepIndex() == 0
? { '.fr-form-step-footer': { display: 'none' } }
: {}),
: {
'.fr-card-header': {
// Heuristic to prevent width jumpiness between first and second step
minWidth: npsOptions.length * 51,
},
}),
'.fr-form': {
padding: '20px',
'@media (max-width: 660px)': {
minWidth: '100%',
},
},
'.fr-nps-field': {
'@media (min-width: 660px)': {
minWidth: '600px',
minWidth: 'fit-content',
},
minWidth: '100%',
},
Expand All @@ -47,6 +104,9 @@ export function NPS({ as = Dialog, flowId, fieldTypes, part, ...props }: FormPro
gap: '1',
},
},
'.fr-nps': {
maxWidth: 'min-content',
},
...((props.css as object) ?? {}),
},
}}
Expand Down
27 changes: 19 additions & 8 deletions packages/react/src/components/Survey/NPSField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,29 @@ import { Flex } from '@/components/Flex'
import { FormFieldProps } from '@/components/Form'
import { Text } from '@/components/Text'

export function NPSField({ field, fieldData, submit }: FormFieldProps) {
const buttons = [...Array(11)].map((_, i) => {
const Component = field.value === i ? Button.Primary : Button.Secondary
export function NPSField({
field,
fieldData,
submit,
options,
positiveLabel,
negativeLabel,
}: FormFieldProps & {
options: { label: string; value: string }[]
positiveLabel?: string
negativeLabel?: string
}) {
const buttons = options.map((option) => {
const Component = field.value === option.value ? Button.Primary : Button.Secondary
return (
<Component
borderWidth="1px"
key={i}
key={option.value}
onClick={() => {
field.onChange(i)
field.onChange(option.value)
submit()
}}
title={`${i}`}
title={option.label}
css={{
'.fr-button-title': {
fontSize: '15px',
Expand All @@ -41,10 +52,10 @@ export function NPSField({ field, fieldData, submit }: FormFieldProps) {
</Flex.Row>
<Flex.Row justifyContent="space-between" part="field-nps-label">
<Text.Caption part="field-nps-left-label" color="neutral.400">
{fieldData.negativeLabel ?? `Not likely at all`}
{fieldData.negativeLabel ?? negativeLabel}
</Text.Caption>
<Text.Caption part="field-nps-right-label" color="neutral.400">
{fieldData.positiveLabel ?? `Extremely likely`}
{fieldData.positiveLabel ?? positiveLabel}
</Text.Caption>
</Flex.Row>
</Flex.Column>
Expand Down

0 comments on commit 991ebe2

Please sign in to comment.