-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(feedback): add feedback form (#399)
* feat(feedback): add feedback form * feat(feedback): add test * fix: enable feedback for non-JS browser * refactor: split UserFeedback into sub-components * refactor: rename helpful -> rating --------- Co-authored-by: Pram Gurusinga <[email protected]> Co-authored-by: Joschka de Cuveland <[email protected]>
- Loading branch information
1 parent
92842d4
commit e184e5f
Showing
11 changed files
with
396 additions
and
123 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import { z } from "zod"; | ||
import { withZod } from "@remix-validated-form/with-zod"; | ||
import { ValidatedForm } from "remix-validated-form"; | ||
import CloseIcon from "@mui/icons-material/CloseOutlined"; | ||
import SendIcon from "@mui/icons-material/SendOutlined"; | ||
import Button from "../Button"; | ||
import ButtonContainer from "../ButtonContainer"; | ||
import Heading from "../Heading"; | ||
import Textarea from "../Textarea"; | ||
|
||
export const feedbackFormName = "feedbackForm"; | ||
const feedbackFieldname = "feedback"; | ||
const feedbackButtonFieldname = "feedbackButton"; | ||
|
||
enum FeedbackButtons { | ||
Abort = "abort", | ||
Submit = "submit", | ||
} | ||
|
||
export const feedbackValidator = withZod( | ||
z.object({ | ||
feedback: z | ||
.string() | ||
.refine( | ||
(feedback) => !/\s0\d/.test(feedback), | ||
"Bitte geben sie keine Telefonnummer ein.", | ||
) | ||
.refine( | ||
(feedback) => !feedback.includes("@"), | ||
"Bitte geben sie keine E-Mailadresse ein.", | ||
), | ||
}), | ||
); | ||
|
||
export interface FeedbackBoxProps { | ||
destination: string; | ||
heading: string; | ||
placeholder: string; | ||
abortButtonLabel: string; | ||
submitButtonLabel: string; | ||
} | ||
|
||
export const FeedbackFormBox = ({ | ||
destination, | ||
heading, | ||
placeholder, | ||
abortButtonLabel, | ||
submitButtonLabel, | ||
}: FeedbackBoxProps) => ( | ||
<> | ||
<Heading look="ds-label-01-bold" tagName="h2" text={heading} /> | ||
<ValidatedForm | ||
validator={feedbackValidator} | ||
subaction={feedbackFormName} | ||
method="post" | ||
action={destination} | ||
> | ||
<div className="ds-stack-16"> | ||
<Textarea name={feedbackFieldname} placeholder={placeholder} /> | ||
<ButtonContainer> | ||
<Button | ||
iconLeft={<CloseIcon />} | ||
look="tertiary" | ||
name={feedbackButtonFieldname} | ||
value={FeedbackButtons.Abort} | ||
type="submit" | ||
> | ||
{abortButtonLabel} | ||
</Button> | ||
<Button | ||
look="primary" | ||
iconLeft={<SendIcon />} | ||
name={feedbackButtonFieldname} | ||
value={FeedbackButtons.Submit} | ||
type="submit" | ||
> | ||
{submitButtonLabel} | ||
</Button> | ||
</ButtonContainer> | ||
</div> | ||
</ValidatedForm> | ||
</> | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import Heading from "../Heading"; | ||
import RichText from "../RichText"; | ||
|
||
export interface PostSubmissionBoxProps { | ||
heading: string; | ||
text: string; | ||
} | ||
|
||
export const PostSubmissionBox = ({ | ||
heading, | ||
text, | ||
}: PostSubmissionBoxProps) => ( | ||
<div data-testid="user-feedback-submission"> | ||
<Heading look="ds-label-01-bold" tagName="h2" text={heading} /> | ||
<RichText markdown={text} /> | ||
</div> | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { useEffect, useState } from "react"; | ||
import { useFetcher } from "@remix-run/react"; | ||
import ThumbDownIcon from "@mui/icons-material/ThumbDownOutlined"; | ||
import ThumbUpIcon from "@mui/icons-material/ThumbUpOutlined"; | ||
import Button from "../Button"; | ||
import ButtonContainer from "../ButtonContainer"; | ||
import Heading from "../Heading"; | ||
|
||
export const userRatingFieldname = "wasHelpful"; | ||
|
||
export interface RatingBoxProps { | ||
heading: string; | ||
url: string; | ||
context?: string; | ||
yesButtonLabel: string; | ||
noButtonLabel: string; | ||
} | ||
|
||
export const RatingBox = ({ | ||
heading, | ||
url, | ||
context, | ||
yesButtonLabel, | ||
noButtonLabel, | ||
}: RatingBoxProps) => { | ||
const ratingFetcher = useFetcher(); | ||
const [jsAvailable, setJsAvailable] = useState(false); | ||
useEffect(() => setJsAvailable(true), []); | ||
|
||
return ( | ||
<> | ||
<Heading look="ds-label-01-bold" tagName="h2" text={heading} /> | ||
<ratingFetcher.Form | ||
method="post" | ||
action={`/action/send-rating?url=${url}&context=${ | ||
context ?? "" | ||
}&js=${String(jsAvailable)}`} | ||
> | ||
<ButtonContainer> | ||
<Button | ||
iconLeft={<ThumbUpIcon />} | ||
look="tertiary" | ||
name={userRatingFieldname} | ||
value="yes" | ||
type="submit" | ||
> | ||
{yesButtonLabel} | ||
</Button> | ||
<Button | ||
iconLeft={<ThumbDownIcon />} | ||
look="tertiary" | ||
name={userRatingFieldname} | ||
value="no" | ||
type="submit" | ||
> | ||
{noButtonLabel} | ||
</Button> | ||
</ButtonContainer> | ||
</ratingFetcher.Form> | ||
</> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { useLocation } from "@remix-run/react"; | ||
import Background from "../Background"; | ||
import Container from "../Container"; | ||
import { | ||
type PostSubmissionBoxProps, | ||
PostSubmissionBox, | ||
} from "./PostSubmissionBox"; | ||
import { type FeedbackBoxProps, FeedbackFormBox } from "./FeedbackFormBox"; | ||
import { type RatingBoxProps, RatingBox } from "./RatingBox"; | ||
|
||
export enum BannerState { | ||
ShowRating = "showRating", | ||
ShowFeedback = "showFeedback", | ||
FeedbackGiven = "feedbackGiven", | ||
} | ||
|
||
type UserFeedbackProps = { | ||
bannerState: BannerState; | ||
rating: Omit<RatingBoxProps, "url">; | ||
feedback: Omit<FeedbackBoxProps, "destination">; | ||
postSubmission: PostSubmissionBoxProps; | ||
}; | ||
|
||
export default function UserFeedback(props: Readonly<UserFeedbackProps>) { | ||
const { pathname } = useLocation(); | ||
|
||
return ( | ||
<Background paddingTop="32" paddingBottom="40" backgroundColor="white"> | ||
<Container | ||
paddingTop="32" | ||
paddingBottom="32" | ||
overhangingBackground | ||
backgroundColor="midBlue" | ||
> | ||
<div className="ds-stack-16" data-testid="user-feedback-banner"> | ||
{ | ||
{ | ||
[BannerState.ShowRating]: ( | ||
<RatingBox url={pathname} {...props.rating} /> | ||
), | ||
[BannerState.ShowFeedback]: ( | ||
<FeedbackFormBox destination={pathname} {...props.feedback} /> | ||
), | ||
[BannerState.FeedbackGiven]: ( | ||
<PostSubmissionBox {...props.postSubmission} /> | ||
), | ||
}[props.bannerState] | ||
} | ||
</div> | ||
</Container> | ||
</Background> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.