Skip to content

Commit

Permalink
Revert "Revert "Plan-F Fahrradcheck (#48)""
Browse files Browse the repository at this point in the history
This reverts commit 3f343cc.
  • Loading branch information
JohannaPeanut committed Sep 18, 2023
1 parent 1f9683d commit aba518c
Show file tree
Hide file tree
Showing 27 changed files with 23,197 additions and 17,647 deletions.
39,370 changes: 21,783 additions & 17,587 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@
"gatsby-source-strapi": "^3.3.0",
"gatsby-transformer-remark": "^6.11.0",
"gatsby-transformer-sharp": "^5.11.0",
"query-string": "^7.1.1",
"react": "^18.2.0",
"react-aria-components": "^1.0.0-alpha.6",
"react-dom": "^18.2.0",
"tsconfig-paths-webpack-plugin": "^4.1.0"
},
Expand Down
2 changes: 1 addition & 1 deletion src/components/AwardPage/FotoCopyright.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export const FotoCopyright: React.FC<Props> = ({
preload = true,
}) => {
return (
<div className="py-4">
<div className="py-4 prose-figcaption:text-gray-400 prose-figcaption:mt-3">
<img src={src} alt={copyright} loading={preload ? 'eager' : 'lazy'} />
<figcaption>Foto:&nbsp;&copy;&nbsp;{copyright}</figcaption>
</div>
Expand Down
24 changes: 12 additions & 12 deletions src/components/ExamplePage/InfoPopover.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { Popover } from '@headlessui/react';
import { ReactNode } from 'react';
import { InformationCircleIcon } from '@heroicons/react/24/outline';
import { Popover } from '../Layout/Popover';

type Props = {
children: any;
button: ReactNode;
label: React.ReactNode;
};

export const InfoPopover: React.FC<Props> = ({ children, button }) => {
export const InfoPopover: React.FC<Props> = ({ label }) => {
return (
<Popover className="relative">
<Popover.Button>{button}</Popover.Button>

<Popover.Panel className="absolute z-[1] w-full bg-black px-4 sm:ml-8">
{children}
</Popover.Panel>
</Popover>
<Popover
button={<InformationCircleIcon className="h-6 w-6 text-gray-900" />}
label={
<div className="p-4 bg-black text-white leading-snug max-w-sm text-sm m-2 ml-6">
{label}
</div>
}
/>
);
};
8 changes: 3 additions & 5 deletions src/components/Layout/CardPageTeaser.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { ArrowRightIcon } from '@heroicons/react/20/solid';
import clsx from 'clsx';
import React, { ReactNode } from 'react';
import { H2, P } from '../Text';
import { Link } from '../core/links';
import { LinkButtonWithArrowBlack } from './LinkButtonWithArrowBlack';

type Props = {
title: string;
Expand All @@ -21,10 +20,9 @@ export const PageTeaserCard: React.FC<Props> = ({
<section className={clsx('bg-gray-50 p-5', className)}>
<H2 className="!mt-0">{title}</H2>
<P>{children}</P>
<Link className="mt-6 flex items-center gap-2" button="black" href={link}>
<ArrowRightIcon className="h-5 w-5 " />
<LinkButtonWithArrowBlack href={link}>
Weiterlesen
</Link>
</LinkButtonWithArrowBlack>
</section>
);
};
4 changes: 2 additions & 2 deletions src/components/Layout/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ const Layout: React.FC<
<SideNavigation path={path} />
</div>
)}
<div className="flex-grow">
<main>{children}</main>
<div className="flex-grow max-w-full">
<main className="max-w-full">{children}</main>
<Footer />
</div>
</div>
Expand Down
27 changes: 27 additions & 0 deletions src/components/Layout/LinkButtonWithArrowBlack.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { ArrowRightIcon } from '@heroicons/react/20/solid';
import clsx from 'clsx';
import React, { ReactNode } from 'react';
import { Link } from '../core/links';

type Props = {
children: ReactNode;
className?: string;
href: string;
};

export const LinkButtonWithArrowBlack: React.FC<Props> = ({
children,
className,
href,
}) => {
return (
<Link
className={clsx(className, 'mt-6 flex items-center gap-2')}
button="black"
href={href}
>
<ArrowRightIcon className="h-5 w-5 " />
{children}
</Link>
);
};
1 change: 1 addition & 0 deletions src/components/Layout/Navigation/menuItems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { wikiPath } from '~/components/utils';

export const menuItems = {
Wissensspeicher: `/${wikiPath}/`,
'Plan F Check': `/plan-f-check/`,
'Weitere Angebote': '/weitere-angebote/',
Artikel: '/artikel/',
Über: '/ueber/',
Expand Down
23 changes: 23 additions & 0 deletions src/components/Layout/Popover.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/* eslint-disable import/no-extraneous-dependencies */
import {
Button,
Dialog,
DialogTrigger,
Popover as ReactAriaPopover,
} from 'react-aria-components';

type Props = {
button: React.ReactNode;
label: React.ReactNode;
};

export const Popover: React.FC<Props> = ({ button, label }) => {
return (
<DialogTrigger>
<Button>{button}</Button>
<ReactAriaPopover>
<Dialog>{label}</Dialog>
</ReactAriaPopover>
</DialogTrigger>
);
};
5 changes: 4 additions & 1 deletion src/components/MeasurePage/CardExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,18 @@ type Props = {
image: any;
children: ReactNode;
title: string;
linkExternal?: boolean;
};
export const CardExample: React.FC<Props> = ({
children,
link,
image,
title,
linkExternal,
}) => {
return (
<Link
external={linkExternal}
button="card"
className="flex h-full flex-col rounded-b-3xl bg-white"
href={link}
Expand All @@ -28,7 +31,7 @@ export const CardExample: React.FC<Props> = ({
image={getImage(image.image.localFile as any)}
/>
{image.copyright && (
<p className="px-5 pt-2 text-right text-xs text-gray-700">
<p className="px-5 pt-2 text-right text-xs text-gray-400">
Abbildung: {image.copyright}
</p>
)}
Expand Down
46 changes: 46 additions & 0 deletions src/components/PlanFCheck/CardTopicPlanFCheckPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import clsx from 'clsx';
import React, { ReactNode } from 'react';
import { Link } from '../core/links/Link';

type Props = {
link: string;
image?: string;
children: ReactNode;
className?: string;
title: string;
linkExternal?: boolean;
};
export const CardTopicPlanFCheck: React.FC<Props> = ({
className,
children,
link,
image,
title,
linkExternal,
}) => {
return (
<Link
external={linkExternal}
button="card"
className={clsx(
'flex h-full flex-col gap-3 rounded-b-3xl bg-white p-6 sm:flex-row sm:gap-12',
className,
)}
href={link}
>
{image && (
<img
src={image}
className="h-24 w-24 flex-shrink-0 overflow-hidden"
alt={`Titelbild ${link}`}
/>
)}
<div>
<h3 className="text-black md:text-xl mb-2 text-lg font-bold">
{title}
</h3>
{children}
</div>
</Link>
);
};
89 changes: 89 additions & 0 deletions src/components/PlanFCheck/Question.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { RadioGroup } from '@headlessui/react';
import clsx from 'clsx';
import React, { useState } from 'react';
import { Content } from '../Layout';
import { Section } from '../Layout/Section';
import { H3 } from '../Text';
import { Question } from './questions.const';
import { InfoPopover } from '../ExamplePage/InfoPopover';

type Props = {
question: Question;
setSurveyResult: any;
surveyResult: any;
className?: string;
isSubmit: boolean;
};

export const QuestionItem: React.FC<Props> = ({
question,
setSurveyResult,
surveyResult,
className,
isSubmit,
}) => {
const [questionResult, setQuestionResult] = useState(null);

return (
<Section
className={clsx(
className,
'py-10 md:py-16',
'mt-4 group hover:bg-white hover:shadow-xl rounded-b-none',
)}
>
<Content>
<div className="flex justify-between items-start mb-4 gap-4">
<H3 className="!mt-0 !md:mt-0">
{question.id + 1}. {question.question}
</H3>
{question.explanation && (
<InfoPopover label={<p>{question.explanation}</p>} />
)}
</div>
<RadioGroup
value={questionResult}
onChange={(x) => {
setQuestionResult(x);
const newSurveResult = [...surveyResult];
newSurveResult[question.id] = x;
setSurveyResult(newSurveResult);
console.log({ newSurveResult });
}}
>
<div className="grid grid-cols-2 sm:grid-cols-3 gap-3 md:grid-cols-5">
{question.options.map((option, i) => (
<RadioGroup.Option
key={option.text}
value={i}
className={({ active, checked }) =>
clsx(
active ? 'ring-2 ring-purple-300 ring-offset-2' : '',
checked
? 'bg-purple-200 hover:bg-purple-300'
: 'ring-1 ring-inset ring-gray-300 bg-white text-gray-900 hover:bg-gray-100',
'flex items-center justify-center rounded-md py-3 px-3 text-sm font-semibold uppercase sm:flex-1 hover:cursor-pointer',
)
}
>
<RadioGroup.Label
className="lowercase whitespace-nowrap text-xs md:text-sm"
as="span"
>
{option.text}
</RadioGroup.Label>
</RadioGroup.Option>
))}
</div>
{isSubmit && questionResult === null && (
<p className="text-red-500 text-xs mt-4 pt-3">
* Das Beantworten aller Fragen ist verpflichtend, um den
Fragebogen abschließen zu können. Bitte wählen Sie eine Antwort
auf diese Frage!
</p>
)}
</RadioGroup>
</Content>
</Section>
);
};
77 changes: 77 additions & 0 deletions src/components/PlanFCheck/calculateScore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import {
allQuestions,
Topic,
Measure,
MeasureType,
Question,
} from './questions.const';

export const calculateScore = (answers: number[], questions: Question[]) => {
if (answers.length !== questions.length) {
throw Error(
`lengths of answers (${answers.length}) and questions (${questions.length}) don't match`,
);
}
const topicScores: Record<Topic, number> = Object.create(null);
const measureScores: Record<Measure, number> = Object.create(null);
const measureTypeScores: Record<MeasureType, number> = Object.create(null);
const topicMaxScores: Record<Topic, number> = Object.create(null);
const measureMaxScores: Record<Measure, number> = Object.create(null);
const measureTypeMaxScores: Record<MeasureType, number> = Object.create(null);
let totalScore = 0;
let totalMaxScore = 0;
answers.forEach((answer, i) => {
const question = allQuestions[i];
const optionsWeights = question.options.map((x) => x.weight);
const score = optionsWeights[answer] * question.weight;
const maxScore = question.weight * Math.max(...optionsWeights);
totalScore += score;
totalMaxScore += maxScore;
const updateScore = <T extends string>(
obj: Record<T, number>,
key: T,
val: number,
) => {
if (obj[key] == null) {
// eslint-disable-next-line no-param-reassign
obj[key] = val;
} else {
// eslint-disable-next-line no-param-reassign
obj[key] += val;
}
};
question.topics.forEach((topic: Topic) => {
updateScore(topicScores, topic, score);
updateScore(topicMaxScores, topic, maxScore);
});
question.measures.forEach((measure: Measure) => {
updateScore(measureScores, measure, score);
updateScore(measureMaxScores, measure, maxScore);
});
question.measureTypes.forEach((measureType: MeasureType) => {
updateScore(measureTypeScores, measureType, score);
updateScore(measureTypeMaxScores, measureType, maxScore);
});
});
totalScore /= totalMaxScore;
Object.keys(topicScores).forEach((topic: Topic) => {
topicScores[topic] /= topicMaxScores[topic];
topicScores[topic] = Math.round(topicScores[topic] * 100);
});
Object.keys(measureScores).forEach((measure: Measure) => {
measureScores[measure] /= measureMaxScores[measure];
measureScores[measure] = Math.round(measureScores[measure] * 100);
});
Object.keys(measureTypeScores).forEach((measureType: MeasureType) => {
measureTypeScores[measureType] /= measureTypeMaxScores[measureType];
measureTypeScores[measureType] = Math.round(
measureTypeScores[measureType] * 100,
);
});
return {
totalScore,
topicScores,
measureScores,
measureTypeScores,
};
};
2 changes: 2 additions & 0 deletions src/components/PlanFCheck/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './calculateScore';
export * from './questions.const';
Loading

0 comments on commit aba518c

Please sign in to comment.