Skip to content

Commit

Permalink
Merge branch 'main' into programmatic-email-and-download
Browse files Browse the repository at this point in the history
  • Loading branch information
HendrikSchmidt committed Sep 27, 2024
2 parents 6cb9329 + 19d9fdf commit 43749ea
Show file tree
Hide file tree
Showing 23 changed files with 429 additions and 118 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/scan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
exit-code: "1" # Fail the build!

- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@294a9d92911152fe08befb9ec03e240add280cb3 # v3.26.8
uses: github/codeql-action/upload-sarif@461ef6c76dfe95d5c364de2f431ddbd31a417628 # v3.26.9
if: always() # Bypass non-zero exit code..
with:
sarif_file: "trivy-results.sarif"
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"@commitlint/types": "^19.5.0",
"@playwright/test": "^1.47.1",
"@testing-library/jest-dom": "^6.4.6",
"@types/node": "^22.6.0",
"@types/node": "^22.7.1",
"@types/react": "^18.2.18",
"@types/react-dom": "^18.2.7",
"@typescript-eslint/eslint-plugin": "^8.7.0",
Expand Down
201 changes: 150 additions & 51 deletions packages/dito/app/components/FeedbackForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,53 +4,72 @@ import RichText from "@digitalcheck/shared/components/RichText";
import ThumbDownOutlined from "@digitalservicebund/icons/ThumbDownOutlined";
import ThumbUpOutlined from "@digitalservicebund/icons/ThumbUpOutlined";
import classNames from "classnames";
import React, { useState, type ReactNode } from "react";
import React, { useEffect, useRef, useState } from "react";
import { feedbackForm } from "resources/content";

const TRACKING_CLASS = "plausible-event-name=Feedback plausible-event-question";

function FeedbackButton({
function FeedbackInput({
children,
value,
selected,
onClick,
trackingClass,
onChange,
name,
id,
ariaLabel,
}: Readonly<{
children: ReactNode;
children: React.ReactNode;
value: number;
selected: boolean;
onClick: React.MouseEventHandler<HTMLButtonElement>;
trackingClass?: string;
onChange: React.ChangeEventHandler<HTMLInputElement>;
name: string;
id: string;
ariaLabel: string;
}>) {
const classes = classNames(
`rounded-lg px-24 h-64 flex items-center gap-8 ${trackingClass}`,
{
"bg-blue-200 text-blue-800 fill-blue-800 active:bg-blue-800 active:text-white active:fill-white":
!selected,
},
{ "bg-blue-800 text-white fill-white": selected },
);
const classes = classNames(`rounded-lg px-24 h-64 flex items-center gap-8`, {
"bg-blue-200 text-blue-800": !selected,
"bg-blue-800 text-white": selected,
});

return (
<button className={classes} value={value} onClick={onClick}>
<label className={classes}>
<input
type="radio"
name={name}
id={id}
value={value}
checked={selected}
onChange={onChange}
aria-label={ariaLabel}
className="sr-only"
/>
{children}
</button>
</label>
);
}

function FeedbackQuestion({
legend,
trackingClass,
isBinary = false,
}: Readonly<{ legend: string; trackingClass?: string; isBinary?: boolean }>) {
const [selected, setSelected] = useState<number | null>();
name,
isLast = false,
}: Readonly<{
legend: string;
isBinary?: boolean;
name: string;
isLast?: boolean;
}>) {
const [selected, setSelected] = useState<number | null>(null);

const onClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setSelected(Number(event.currentTarget.value));
const onChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setSelected(Number(event.target.value));
};

return (
<fieldset className="flex flex-col lg:flex-row gap-20 lg:gap-24 pt-24 pb-20 border-b-2 border-blue-300 last:border-0">
<fieldset
className={classNames(
"flex flex-col lg:flex-row gap-20 lg:gap-24 pt-24 pb-20 border-blue-300",
{ "border-b-2": !isLast }, // conditional rendering because last:border-b-0 doesn't work here
)}
>
<div className="lg:w-1/2">
<legend>
<p>{legend}</p>
Expand All @@ -59,42 +78,68 @@ function FeedbackQuestion({
<div className="lg:w-1/2">
{isBinary ? (
<div className="flex gap-16">
<FeedbackButton
<FeedbackInput
value={1}
selected={selected === 1}
onClick={onClick}
trackingClass={`${trackingClass}Ja`}
onChange={onChange}
name={name}
id={`${name}-yes`}
ariaLabel="Ja"
>
<ThumbUpOutlined />
<span className="ds-label-01-bold">Ja</span>
</FeedbackButton>
<FeedbackButton
</FeedbackInput>
<FeedbackInput
value={2}
selected={selected === 2}
onClick={onClick}
trackingClass={`${trackingClass}Nein`}
onChange={onChange}
name={name}
id={`${name}-no`}
ariaLabel="Nein"
>
<ThumbDownOutlined />
<span className="ds-label-01-bold">Nein</span>
</FeedbackButton>
</FeedbackInput>
</div>
) : (
<div className="max-w-fit">
<div className="flex gap-16">
{[1, 2, 3, 4, 5].map((number) => (
<FeedbackButton
key={number}
value={number}
selected={selected === number}
onClick={onClick}
trackingClass={`${trackingClass}${number}`}
>
<span className="ds-heading-02-reg">{number}</span>
<span className="sr-only">
{feedbackForm.labels[number - 1]}
</span>
</FeedbackButton>
))}
{[1, 2, 3, 4, 5].map((number) => {
let ariaLabel: string;
switch (number) {
case 1:
ariaLabel = "sehr schwierig";
break;
case 2:
ariaLabel = "schwierig";
break;
case 3:
ariaLabel = "mittel";
break;
case 4:
ariaLabel = "einfach";
break;
case 5:
ariaLabel = "sehr einfach";
break;
default:
ariaLabel = "";
}

return (
<FeedbackInput
key={number}
value={number}
selected={selected === number}
onChange={onChange}
name={name}
id={`${name}-${number}`}
ariaLabel={ariaLabel}
>
<span className="ds-heading-02-reg">{number}</span>
</FeedbackInput>
);
})}
</div>
<div className="mt-20 text-gray-900 flex justify-between">
<span className="">{feedbackForm.labels[0]}</span>
Expand All @@ -108,20 +153,74 @@ function FeedbackQuestion({
}

export default function FeedbackForm() {
const [submitted, setSubmitted] = useState(false);
const thankYouMessageRef = useRef<HTMLDivElement>(null);

const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();

const formData = new FormData(event.currentTarget);
const simpleFeedback = formData.get("simple-feedback");
const usefulFeedback = formData.get("useful-feedback");

// Plausible event trigger with feedback values
if (window.plausible) {
window.plausible("Feedback Methoden", {
props: {
questionSimple: simpleFeedback?.toString() || "No Feedback",
questionUseful: usefulFeedback?.toString() || "No Feedback",
},
});
}

setSubmitted(true);
};

// After submission, move focus to the thanks message for accessibility
useEffect(() => {
if (submitted && thankYouMessageRef.current) {
thankYouMessageRef.current.focus();
}
}, [submitted]);

if (submitted) {
return (
<div ref={thankYouMessageRef} tabIndex={-1} aria-live="polite">
<Background backgroundColor="blue" paddingTop="40" paddingBottom="48">
<Container backgroundColor="white" overhangingBackground>
<h2>Vielen Dank für Ihr Feedback!</h2>
<br />
<p>
Wir schätzen Ihre Rückmeldung sehr und werden sie in unsere
Verbesserungen einfließen lassen.
</p>
</Container>
</Background>
</div>
);
}

return (
<Background backgroundColor="blue" paddingTop="40" paddingBottom="48">
<Container backgroundColor="white" overhangingBackground>
<h2>{feedbackForm.heading}</h2>
<div className="mb-48">
<form onSubmit={handleSubmit} className="mb-48">
<FeedbackQuestion
legend={feedbackForm.questionSimple}
trackingClass={`${TRACKING_CLASS}Simple=`}
name="simple-feedback"
/>
<FeedbackQuestion
legend={feedbackForm.questionUseful}
trackingClass={`${TRACKING_CLASS}Useful=`}
name="useful-feedback"
isLast={true}
/>
</div>
<button
type="submit"
className="mt-16 bg-blue-800 text-white px-24 py-12 rounded-lg"
>
Feedback absenden
</button>
</form>
<RichText markdown={feedbackForm.mail} className="ds-label-01-bold" />
</Container>
</Background>
Expand Down
3 changes: 3 additions & 0 deletions packages/dito/app/global.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
interface Window {
plausible: (eventName: string, options) => void;
}
Loading

0 comments on commit 43749ea

Please sign in to comment.