Skip to content

Commit

Permalink
Survey radnetz brandenburg update: Modal, Survey Response Email (#105)
Browse files Browse the repository at this point in the history
  • Loading branch information
JohannaPeanut authored Jun 17, 2024
2 parents 29006b2 + 6392fac commit 39506ae
Show file tree
Hide file tree
Showing 11 changed files with 360 additions and 30 deletions.
154 changes: 154 additions & 0 deletions mailers/surveyFeedbackMailer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import Mailjet from "node-mailjet"
import previewEmail from "preview-email"
import { getPrdOrStgDomain } from "src/core/components/links/getDomain"

type SurveyFeedbackMailer = {
userMail: string
userFirstname: string
userLastname: string
feedbackLocation: { lng: number; lat: number }
feedbackCategory: string
feedbackText: string
lineID: string
}

export function surveyFeedbackMailer({
userMail,
userFirstname,
userLastname,
feedbackLocation,
feedbackCategory,
feedbackText,
lineID,
}: SurveyFeedbackMailer) {
const origin = getPrdOrStgDomain()
// mailjet format
const msg = {
From: { Email: "<[email protected]>", Name: "Trassenscout" },
To: [{ Email: userMail }],
Subject: "Beteiligung zum Radnetz Brandenburg: Ihr eingereichter Hinweis",
TextPart: `
Guten Tag, ${userFirstname} ${userLastname},
vielen Dank für Ihre Teilnahme! Hiermit bestätigen wir Ihnen den Eingang Ihres Beitrags mit folgenden Angaben:
Eingangsdatum: ${new Date().toLocaleDateString("de-DE")}
Kategorie: ${feedbackCategory}
ID der gewählten Verbindung im Netzentwurf: ${lineID}
Ihr Hinweis:
${feedbackText}
Ortsbezug des Beitrags (in OpenStreetMap): https://www.openstreetmap.org/?mlat=${
feedbackLocation.lat
}&mlon=${feedbackLocation.lng}=16
Hinweis: Beachten Sie, dass Sie für jeden eingereichten Hinweis eine separate E-Mail erhalten. Dies ist eine automatisiert versandte E-Mail, auf die Sie nicht antworten können.
Nach Abschluss der Beteiligung werden Ihre Hinweise fachlich geprüft und in die Abwägung zur Überarbeitung des Zielnetzentwurfs mit einbezogen.
Mit freundlichen Grüßen
i.A. das Team von FixMyCity
FixMyCity GmbH
Oberlandstraße 26-35
12099 Berlin
mail: [email protected]
www.fixmycity.de
`,
HTMLPart: `
<p>
Guten Tag, ${userFirstname} ${userLastname},
</p>
<p>
vielen Dank für Ihre Teilnahme! Hiermit bestätigen wir Ihnen den Eingang Ihres Beitrags mit
folgenden Angaben:
</p>
<p>
Eingangsdatum: ${new Date().toLocaleDateString("de-DE")} <br/>
Kategorie: ${feedbackCategory} <br />
ID der gewählten Verbindung im Netzentwurf: ${lineID}
<br />
Ihr Hinweis: <br />
<i>${feedbackText}</i>
<br />
<a target="_blank"
href=https://www.openstreetmap.org/?mlat=${feedbackLocation.lat}&mlon=${
feedbackLocation.lng
}=16
>
Ortsbezug des Beitrags (in OpenStreetMap)
</a>
</p>
<p>
<i>Hinweis:</i>
Beachten Sie, dass Sie für jeden eingereichten Hinweis eine separate E-Mail erhalten. Dies
ist eine automatisiert versandte E-Mail, auf die Sie nicht antworten können.
</p>
<p>
Nach Abschluss der Beteiligung werden Ihre Hinweise fachlich geprüft und in die Abwägung zur
Überarbeitung des Zielnetzentwurfs mit einbezogen.
</p>
<p>
Mit freundlichen Grüßen <br />
i.A. das Team von FixMyCity
</p>
<p>
<small>FixMyCity GmbH</small>
<br />
<small>Oberlandstraße 26-35</small>
<br />
<small>12099 Berlin</small>
<br />
<small>
mail: <a href="mailto:[email protected]">[email protected]</a>
</small>
<br />
<small>
<a href="https://www.fixmycity.de/">www.fixmycity.de</a>
</small>
<br />
<small>
<a href="https://de.linkedin.com/company/fixmycity?trk=public_profile_topcard-current-company">
LinkedIn
</a>
</small>
</p>
<img
src="https://images.squarespace-cdn.com/content/v1/605af904f08f5246bc415204/1616576639935-WCJVD5JU8LNMBBSFIYHV/Logo_Positiv%402x.png?format=1500w"
alt="FixMyCity Logo"
width="60"
/>
`,
}

return {
async send() {
if (process.env.NODE_ENV !== "development") {
const mailjet = Mailjet.apiConnect(
// @ts-ignore
process.env.MAILJET_APIKEY_PUBLIC,
process.env.MAILJET_APIKEY_PRIVATE,
)
const request = mailjet.post("send", { version: "v3.1" }).request({ Messages: [msg] })
request
.then((result) => {
console.log(result.body)
})
.catch((err) => {
console.error(err.statusCode)
})
} else {
// Preview email in the browser
var { From, To, Subject, TextPart, HTMLPart } = msg
await previewEmail({
from: `${From.Name} <${From.Email}>`,
// @ts-ignore
to: `${To[0]?.Name || ""} <${To[0].Email}>`,
subject: Subject,
text: TextPart,
html: HTMLPart,
})
}
},
}
}
4 changes: 3 additions & 1 deletion src/survey-public/components/Question.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
TFeedbackQuestion,
TQuestion,
TSingleOrMultiResponseProps,
TTextProps,
Expand Down Expand Up @@ -89,10 +90,11 @@ const components = {
custom: CustomComponent,
}

type Props = { question: TQuestion; className?: string }
type Props = { question: TQuestion | TFeedbackQuestion; className?: string }

export const Question: React.FC<Props> = ({ question, className }) => {
const { id, help, label, component, props } = question
// @ts-expect-error
const Component = components[component] || null
return (
<div className={className} key={id}>
Expand Down
14 changes: 13 additions & 1 deletion src/survey-public/components/SurveyMainPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import { SurveySpinnerLayover } from "src/survey-public/components/core/layout/S
import { Feedback } from "src/survey-public/components/feedback/Feedback"
import { ProgressContext } from "src/survey-public/context/contexts"
import { scrollToTopWithDelay } from "src/survey-public/utils/scrollToTopWithDelay"
import surveyFeedbackEmail from "src/survey-responses/mutations/surveyFeedbackEmail"

import { useParams } from "next/navigation"
import createSurveyResponse from "src/survey-responses/mutations/createSurveyResponse"
import createSurveySession from "src/survey-sessions/mutations/createSurveySession"
import {
Expand All @@ -23,6 +25,7 @@ import {
TResponseConfig,
TSurvey,
} from "./types"
import { useParam } from "@blitzjs/next"

type Props = {
startContent: React.ReactNode
Expand All @@ -33,7 +36,7 @@ type Props = {
surveyDefinition: TSurvey
responseConfig: TResponseConfig
surveyId: number
// clean up after BB ? - initial view state of surveymapline depending on institution
// todo survey clean up or refactor after survey BB ? - initial view state of surveymapline depending on institution
// prop institutionsBboxes might be cleaned up after BB in this and the other components it is passed through
institutionsBboxes?: TInstitutionsBboxes
}
Expand All @@ -57,6 +60,9 @@ export const SurveyMainPage: React.FC<Props> = ({
const [feedbackKey, setFeedbackKey] = useState(1)
const [createSurveySessionMutation] = useMutation(createSurveySession)
const [createSurveyResponseMutation] = useMutation(createSurveyResponse)
const [surveyFeedbackEmailMutation] = useMutation(surveyFeedbackEmail)
const surveySlug = useParam("surveySlug", "string")

useEffect(() => {
const root = document.documentElement
root.style.setProperty("--survey-primary-color", surveyDefinition.primaryColor)
Expand Down Expand Up @@ -117,6 +123,12 @@ export const SurveyMainPage: React.FC<Props> = ({
data: JSON.stringify(feedbackResponses),
source: "FORM",
})
// todo survey clean up or refactor after survey BB
if (surveySlug === "radnetz-brandenburg")
await surveyFeedbackEmailMutation({
surveySessionId: surveySessionId_,
data: feedbackResponses,
})
})()

setTimeout(() => {
Expand Down
4 changes: 2 additions & 2 deletions src/survey-public/components/core/links/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,15 @@ export const surveyWhiteButtonStyles = clsx(

// primary color survey BUTTON
// for link elements
const primaryColorButtonStylesForLinkElement = clsx(
export const primaryColorButtonStylesForLinkElement = clsx(
buttonBase,
"text-white bg-[var(--survey-primary-color)]",
activeStylePrimaryColorLinkElement,
)
// for button elements
export const surveyPrimaryColorButtonStyles = clsx(
buttonBase,
"enabled:text-white enabled:bg-[var(--survey-primary-color)]",
"enabled:text-white bg-[var(--survey-primary-color)]",
"disabled:bg-[var(--survey-light-color)] disabled:text-white",
activeStylePrimaryColorButtonElement,
)
Expand Down
6 changes: 3 additions & 3 deletions src/survey-public/components/feedback/FeedbackFirstPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type Props = {
feedbackCategoryId: number
setIsCompleted: any
institutionsBboxes?: TInstitutionsBboxes
// clean up after BB: legend for line map
// todo survey clean up or refactor after survey BB: legend for line map
legend?: Record<string, Record<string, TLegendItem>>
}

Expand All @@ -34,7 +34,7 @@ export const FeedbackFirstPage: React.FC<Props> = ({
institutionsBboxes,
legend,
}) => {
// clean up after BB ? - initial view state of surveymapline depending on institution
// todo survey clean up or refactor after survey BB ? - initial view state of surveymapline depending on institution
// maybe this logic should be used for SurveyMap in future surveys
const router = useRouter()
const { id } = router.query
Expand All @@ -52,7 +52,7 @@ export const FeedbackFirstPage: React.FC<Props> = ({
return (
<>
<SurveyScreenHeader title={title.de} description={description.de} />
{/* clean up after BB */}
{/* todo survey clean up or refactor after survey BB */}
{/* This map to select a line is custom for BB survey and is going to be deleted afterwards */}
{surveySlug === "radnetz-brandenburg" && (
<>
Expand Down
27 changes: 22 additions & 5 deletions src/survey-public/components/feedback/FeedbackSecondPage.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { SurveyButton } from "../core/buttons/SurveyButton"
import { SurveyButtonWrapper } from "../core/buttons/SurveyButtonWrapper"

import { useFormContext } from "react-hook-form"
import { MapProvider } from "react-map-gl"
import { SurveyScreenHeader } from "src/survey-public/components/core/layout/SurveyScreenHeader"
import { TMapProps, TPage, TQuestion } from "src/survey-public/components/types"
import { TFeedbackQuestion, TMapProps, TPage, TTextProps } from "src/survey-public/components/types"
import { Question } from "../Question"
import { SurveyLabeledTextareaField } from "../core/form/SurveyLabeledTextareaField"
import { SurveyMap } from "../maps/SurveyMap"
import { SurveyMapLegend } from "../maps/SurveyMapLegend"
import { useFormContext } from "react-hook-form"
import { SurveyH2 } from "../core/Text"

export { FORM_ERROR } from "src/core/components/forms"

Expand Down Expand Up @@ -57,7 +59,7 @@ export const FeedbackSecondPage: React.FC<Props> = ({
config: mapProps.config,
}}
pinId={pinId}
// clean up after BB line selection is removed
// todo survey clean up or refactor after survey BB line selection
lineGeometryId={lineGeometryId}
/>

Expand All @@ -66,8 +68,23 @@ export const FeedbackSecondPage: React.FC<Props> = ({
)}
<div className="pt-8">
{userTextIndices.map((questionId) => {
const q = questions!.find((q: TQuestion) => q.id === questionId)
if (q) return <Question key={questionId} question={q} />
const q = questions!.find((q) => q.id === questionId)
if (q) {
const userTextQuestionProps = q.props as TTextProps
return (
<>
<SurveyH2>{q.label.de} *</SurveyH2>
{q.help && <div className="-mt-4 mb-6 text-gray-400 text-sm">{q.help.de}</div>}
<SurveyLabeledTextareaField
key={q.id}
maxLength={200}
name={`text-${q.id}`}
placeholder={userTextQuestionProps.placeholder?.de}
label={""}
/>
</>
)
}
})}
</div>
<SurveyButtonWrapper>
Expand Down
10 changes: 5 additions & 5 deletions src/survey-public/components/maps/SurveyMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export type SurveyMapProps = {
}
setIsMapDirty: any
pinId: number
// clean up after BB line selection is removed
// todo survey clean up or refactor after survey BBline selection
lineGeometryId?: number
}

Expand All @@ -42,8 +42,8 @@ export const SurveyMap: React.FC<SurveyMapProps> = ({
pinId,
className,
setIsMapDirty,
// clean up after BB line selection is removed
lineGeometryId,
// todo survey clean up or refactor after survey BB line selection
}) => {
const { mainMap } = useMap()
const [events, logEvents] = useState<Record<string, LngLat>>({})
Expand All @@ -57,7 +57,7 @@ export const SurveyMap: React.FC<SurveyMapProps> = ({
}
const { getValues, setValue } = useFormContext()

// clean up after BB line selection is removed
// todo survey clean up or refactor after survey BB line selection
// take line geometry from form context
const selectedLine = getValues()[`custom-${lineGeometryId}`] || null
const mapBounds: { bounds: [number, number, number, number] } = {
Expand All @@ -68,7 +68,7 @@ export const SurveyMap: React.FC<SurveyMapProps> = ({
: projectMap.config.bounds,
}

// clean up after BB (center of line option)
// todo survey clean up or refactor after survey BB (center of line option)
// take pinPosition from form context - if it is not defined use center of selected line - if we do not have a selected line use initialMarker fallback from feedback.ts configuration
const pinPosition =
getValues()[`map-${pinId}`] ||
Expand Down Expand Up @@ -154,7 +154,7 @@ export const SurveyMap: React.FC<SurveyMapProps> = ({
// @ts-expect-error: See https://github.com/visgl/react-map-gl/issues/2310
RTLTextPlugin={null}
>
{/* clean up after BB line selection is removed */}
{/* // todo survey clean up or refactor after survey BB line selection */}
{selectedLine && (
<Source
key={"Netzentwurf"}
Expand Down
1 change: 1 addition & 0 deletions src/survey-public/components/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ export type TReadOnlyProps = {
}

export type TFeedbackQuestion = {
help?: TTranslatableText
id: number
label: TTranslatableText
component: "singleResponse" | "multipleResponse" | "text" | "map" | "custom"
Expand Down
Loading

0 comments on commit 39506ae

Please sign in to comment.