Skip to content

Commit

Permalink
feat: add feedback collector form
Browse files Browse the repository at this point in the history
  • Loading branch information
joshuaellis committed Dec 7, 2022
1 parent 1ef0933 commit ee04753
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 15 deletions.
4 changes: 3 additions & 1 deletion docs/app/components/Buttons/GradientButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,16 @@ export const GradientButton = ({
tag,
variant = 'regular',
type = 'button',
...props
}: GradientButtonProps) => {
return (
<Button
size={variant}
className={className}
as={tag}
href={href}
type={tag === 'button' ? type : undefined}>
type={tag === 'button' ? type : undefined}
{...props}>
<span>{children}</span>
</Button>
)
Expand Down
83 changes: 72 additions & 11 deletions docs/app/components/Feedback/Feedback.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from 'react'
import * as Popover from '@radix-ui/react-popover'
import { ThumbsDown, ThumbsUp, X } from 'phosphor-react'
import { useLocation } from '@remix-run/react'
import { useLocation, useFetcher } from '@remix-run/react'

import { Heading } from '~/components/Text/Heading'
import { Copy } from '~/components/Text/Copy'
Expand All @@ -18,6 +18,7 @@ interface FeedbackProps {
}

export const Feedback = ({ location }: FeedbackProps) => {
const [pageTitle, setPageTitle] = React.useState('')
const [selected, setSelected] = React.useState<'upvote' | 'downvote' | null>(
null
)
Expand All @@ -34,11 +35,20 @@ export const Feedback = ({ location }: FeedbackProps) => {
name,
additionalProps: {
location,
title: pageTitle,
},
})
}
}

React.useEffect(() => {
const element = document.querySelector('h1 > a')

if (element) {
setPageTitle(element.innerHTML)
}
}, [])

return (
<div>
<Heading
Expand All @@ -52,14 +62,16 @@ export const Feedback = ({ location }: FeedbackProps) => {
<FeedbackButton
onClick={handleClick('upvote')}
disabled={selected === 'downvote'}
selected={selected === 'upvote'}>
selected={selected === 'upvote'}
pageTitle={pageTitle}>
<ThumbsUp size={16} weight={isDarkMode ? 'light' : 'regular'} />
</FeedbackButton>
<FeedbackButton
onClick={handleClick('downvote')}
disabled={selected === 'upvote'}
selected={selected === 'downvote'}
variant="downvote">
variant="downvote"
pageTitle={pageTitle}>
<ThumbsDown size={16} weight={isDarkMode ? 'light' : 'regular'} />
</FeedbackButton>
</Stack>
Expand All @@ -73,25 +85,41 @@ interface FeedbackButtonProps {
disabled?: boolean
selected?: boolean
variant?: 'upvote' | 'downvote'
pageTitle: string
}

const FeedbackButton = ({
children,
onClick,
pageTitle,
disabled = false,
selected = false,
variant = 'upvote',
}: FeedbackButtonProps) => {
const [isOpen, setIsOpen] = React.useState(false)
const formRef = React.useRef<HTMLFormElement>(null!)
const location = useLocation()
const { data, state, Form } = useFetcher()

const handleClick = () => {
if (onClick) {
onClick()
}
}

const handleOpenChange = (isOpen: boolean) => setIsOpen(isOpen)

React.useEffect(() => {
if (data?.success) {
formRef.current.reset()
setIsOpen(false)
}
}, [data])

const isLoading = state === 'submitting'

return (
<Popover.Root>
<Popover.Root open={isOpen} onOpenChange={handleOpenChange}>
<Trigger disabled={disabled} onClick={handleClick} selected={selected}>
{children}
</Trigger>
Expand All @@ -106,13 +134,29 @@ const FeedbackButton = ({
<X />
</PopoverClose>
</PopoverHeader>
<PopoverForm>
<PopoverInputLabel>
<Form ref={formRef} method="post" action="/api/feedback" replace>
<HiddenInput
name="variant"
type="checkbox"
value={variant}
checked
/>
<HiddenInput name="pageTitle" type="text" value={pageTitle} />
<PopoverInputLabel tag="label">
<span>Feedback</span>
<PopoverInput placeholder="Type your feedback here" type="text" />
<PopoverInput
name="feedback"
placeholder="Type your feedback here"
type="text"
disabled={isLoading}
/>
</PopoverInputLabel>
<PopoverFormFooter>
<PopoverButton variant="small" tag="button" type="submit">
<PopoverButton
aria-disabled={isLoading}
variant="small"
tag="button"
type="submit">
Send
</PopoverButton>
<Outbound
Expand All @@ -129,7 +173,7 @@ const FeedbackButton = ({
: 'Open an issue'}
</Outbound>
</PopoverFormFooter>
</PopoverForm>
</Form>
</PopoverContent>
</Popover.Portal>
</Popover.Root>
Expand Down Expand Up @@ -231,9 +275,8 @@ const PopoverClose = styled(Popover.Close, {
},
})

const PopoverForm = styled('form', {})

const PopoverInputLabel = styled(Copy, {
display: 'block',
mb: '$15',

'& > span': {
Expand All @@ -258,6 +301,15 @@ const PopoverInput = styled('input', {
hover: {
borderColor: '$red100',
},

'&:disabled': {
opacity: 0.5,
pointerEvents: 'none',

hover: {
borderColor: '$steel40',
},
},
})

const PopoverFormFooter = styled('div', {
Expand All @@ -272,6 +324,11 @@ const PopoverButton = styled(GradientButton, {
'& > span': {
background: '$codeBackground',
},

'&[aria-disabled="true"]': {
opacity: 0.5,
pointerEvents: 'none',
},
})

const Outbound = styled(GradientButton, {
Expand All @@ -287,3 +344,7 @@ const Outbound = styled(GradientButton, {
filter: 'brightness(120%)',
},
})

const HiddenInput = styled('input', {
visuallyHidden: '',
})
2 changes: 1 addition & 1 deletion docs/app/components/Text/Copy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export interface CopyProps {
className?: string
children?: ReactNode
css?: CSS
tag?: keyof Pick<JSX.IntrinsicElements, 'p' | 'blockquote' | 'div'>
tag?: keyof Pick<JSX.IntrinsicElements, 'p' | 'blockquote' | 'div' | 'label'>
}

export const Copy = forwardRef<HTMLHeadingElement, CopyProps>(
Expand Down
1 change: 1 addition & 0 deletions docs/app/helpers/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type VotingEvent = EventFactory<
EventNames.DocLiked | EventNames.DocDisliked,
{
location: string
title: string
}
>

Expand Down
37 changes: 37 additions & 0 deletions docs/app/routes/api/feedback.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { ActionFunction, json } from '@remix-run/node'
import { createClient } from '@supabase/supabase-js'

export const action: ActionFunction = async ({ request }) => {
const url = process.env.SUPABASE_URL
const key = process.env.SUPABASE_ANON_KEY

if (!url || !key) {
return json({ error: 'Missing Supabase URL or key' }, 500)
}

const supabase = createClient(url, key, {
db: {
schema: 'public',
},
})

switch (request.method) {
case 'POST': {
try {
const body = await request.formData()

const res = await supabase.from('feedback').insert({
feedback: body.get('feedback'),
page_title: body.get('pageTitle'),
upvoted: body.get('variant') === 'upvote',
})

return json({ success: true }, 200)
} catch (err) {
return json({ success: false, error: err.message }, 405)
}
}
default:
return json({ success: false, error: 'Method not allowed' }, 405)
}
}
2 changes: 0 additions & 2 deletions docs/app/routes/docs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,6 @@ export default function DocsLayout() {

const activeRoute = flatRoutes.find(item => item.href === location.pathname)

console.log(activeRoute)

useEffect(() => {
const element = document.getElementById('carbonads')

Expand Down

0 comments on commit ee04753

Please sign in to comment.