-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Revert "Revert "Plan-F Fahrradcheck (#48)""
This reverts commit 3f343cc.
- Loading branch information
1 parent
1f9683d
commit aba518c
Showing
27 changed files
with
23,197 additions
and
17,647 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
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
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 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 |
---|---|---|
@@ -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> | ||
} | ||
/> | ||
); | ||
}; |
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 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 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,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> | ||
); | ||
}; |
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 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,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> | ||
); | ||
}; |
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 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,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> | ||
); | ||
}; |
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,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> | ||
); | ||
}; |
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,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, | ||
}; | ||
}; |
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,2 @@ | ||
export * from './calculateScore'; | ||
export * from './questions.const'; |
Oops, something went wrong.