Skip to content

Commit

Permalink
improve feedback system so people can provide their email and we stor…
Browse files Browse the repository at this point in the history
…e a record of it in our database
  • Loading branch information
ob6160 committed Sep 1, 2024
1 parent 974464e commit 3b17857
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 59 deletions.
29 changes: 14 additions & 15 deletions schema.prisma
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
generator client {
provider = "prisma-client-js"
previewFeatures = ["multiSchema", "filteredRelationCount", "postgresqlExtensions"]
previewFeatures = ["multiSchema", "postgresqlExtensions"]
}

datasource db {
provider = "postgresql"
url = env("POSTGRES_URI")
extensions = [postgis(schema: "public"), uuid_ossp(map: "uuid-ossp", schema: "extensions")]
extensions = [postgis(schema: "extensions"), uuid_ossp(map: "uuid-ossp", schema: "extensions")]
schemas = ["audit", "public"]
}

Expand All @@ -30,9 +30,9 @@ model record_version {
}

model areas {
id String @id(map: "area_id") @db.Char(24)
id String @id @db.Char(24)
geometry Unsupported("geography")?
name String? @unique(map: "area_name")
name String? @unique
priority Int?
type String?
dataset_id Int?
Expand All @@ -42,18 +42,8 @@ model areas {
@@schema("public")
}

model spatial_ref_sys {
srid Int @id
auth_name String? @db.VarChar(256)
auth_srid Int?
srtext String? @db.VarChar(2048)
proj4text String? @db.VarChar(2048)
@@schema("public")
}

model toilets {
id String @id(map: "toilet_id") @db.Char(24)
id String @id @db.Char(24)
created_at DateTime? @db.Timestamptz(6)
contributors String[]
accessible Boolean?
Expand Down Expand Up @@ -84,6 +74,15 @@ model toilets {
@@schema("public")
}

model feedback {
id Int @id @default(autoincrement())
email String @db.VarChar(255)
feedback_text String
created_at DateTime? @default(now()) @db.Timestamp(6)
@@schema("public")
}

enum operation {
INSERT
UPDATE
Expand Down
37 changes: 19 additions & 18 deletions src/api/prisma/queries.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { Prisma, PrismaClient, toilets, areas } from '@prisma/client';
import { RemovalReportInput } from '../../api-client/graphql';

import { ToiletUpsertReport } from '../graphql/helpers';
import { LooFilter } from '../../@types/resolvers-types';

export const getLooById = async (
prisma: PrismaClient,
id: string
id: string,
): Promise<toilets & { areas: Pick<areas, 'name' | 'type'> }> => {
const res = await prisma.toilets.findUnique({
where: { id },
Expand All @@ -17,7 +15,7 @@ export const getLooById = async (

export const getLooNamesByIds = async (
prisma: PrismaClient,
idList: string[]
idList: string[],
) => {
return prisma.toilets.findMany({
where: {
Expand All @@ -36,7 +34,7 @@ export const setLooLocation = async (
prisma: PrismaClient,
id: string,
lat: number,
lng: number
lng: number,
) => {
return prisma.$executeRaw`
UPDATE toilets SET
Expand All @@ -52,7 +50,7 @@ export const setLooLocation = async (
export const getLoosWithinGeohash = async (
prisma: PrismaClient,
geohash: string,
active = true
active = true,
) =>
prisma.toilets.findMany({
where: {
Expand Down Expand Up @@ -80,7 +78,7 @@ export const getAreas = async (prisma: PrismaClient) =>
export const upsertLoo = async (
prisma: PrismaClient,
report: ToiletUpsertReport,
returnFinal = true
returnFinal = true,
) => {
try {
const result = await prisma.toilets.upsert({
Expand All @@ -97,7 +95,7 @@ export const upsertLoo = async (
prisma,
result.id,
report.extras.location.lat,
report.extras.location.lng
report.extras.location.lng,
);
}

Expand All @@ -114,7 +112,7 @@ export const upsertLoo = async (
export const removeLoo = async (
prisma: PrismaClient,
report: RemovalReportInput,
nickname: string
nickname: string,
) => {
const { edit: id, reason } = report;
return prisma.toilets.update({
Expand Down Expand Up @@ -155,7 +153,7 @@ export const upsertArea = async (
priority: number;
type: string;
version: number;
}
},
) => {
const areaResult = await prisma.areas.upsert({
where: { id: area.id },
Expand Down Expand Up @@ -190,23 +188,26 @@ export const getLoosByProximity = async (
prisma: PrismaClient,
lat: number,
lng: number,
radius = 1000
radius = 1000,
) => {
const nearbyLoos = (await prisma.$queryRaw`
SELECT
loo.id, loo.name, active, men, women, no_payment, notes, opening_times, payment_details,
accessible, active, all_gender, attended, automatic, location, baby_change, children, created_at,
removal_reason, radar, urinal_only, verified_at,updated_at,geohash,
loo.id, loo.name, loo.active, loo.men, loo.women, loo.no_payment, loo.notes, loo.opening_times,
loo.payment_details, loo.accessible, loo.all_gender, loo.attended, loo.automatic, loo.location,
loo.baby_change, loo.children, loo.created_at, loo.removal_reason, loo.radar, loo.urinal_only,
loo.verified_at, loo.updated_at, loo.geohash,
st_distancesphere(
geography::geometry,
loo.geography::geometry,
ST_MakePoint(${lng}, ${lat})
) as distance,
area.name as area_name,
area.type as area_type from toilets loo inner join areas area on area.id = loo.area_id
where st_distancesphere(
area.type as area_type
FROM toilets loo
INNER JOIN areas area ON area.id = loo.area_id
WHERE st_distancesphere(
loo.geography::geometry,
ST_MakePoint(${lng}, ${lat})
) <= ${radius}
) <= ${radius}
`) as (toilets & {
distance: number;
area_name?: string;
Expand Down
48 changes: 27 additions & 21 deletions src/components/Feedback/Feedback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { Stack } from '@mui/material';
import React, { useRef, useState } from 'react';
import Badge from '../../design-system/components/Badge';
import Button from '../../design-system/components/Button';
import Box from '../Box';
import InputField from '../../design-system/components/InputField';
import Link from 'next/link';
import TextArea from '../../design-system/components/TextArea';

enum FeedbackState {
SUCCESS = 0,
Expand All @@ -15,7 +16,6 @@ const Feedback = () => {
const [submitState, setSubmitState] = useState(FeedbackState.PENDING);

const feedbackTextArea = useRef<HTMLTextAreaElement>();
const nameInput = useRef<HTMLInputElement>();
const emailInput = useRef<HTMLInputElement>();

const submitFeedback = async () => {
Expand All @@ -25,13 +25,10 @@ const Feedback = () => {
const hasUserInputText = feedbackTextArea.current?.value.length > 0;

if (hasUserInputText) {
const input = `
Feedback :love_letter: : ${feedbackTextArea.current.value}
Name: ${nameInput.current.value ?? 'Not provided'}
Email: ${emailInput.current.value ?? 'Not provided'}
`;
const input = feedbackTextArea.current.value;
const payload = {
text: input,
email: emailInput.current.value,
};

try {
Expand All @@ -46,8 +43,6 @@ Email: ${emailInput.current.value ?? 'Not provided'}
// eslint-disable-next-line functional/immutable-data
feedbackTextArea.current.value = '';
// eslint-disable-next-line functional/immutable-data
nameInput.current.value = '';
// eslint-disable-next-line functional/immutable-data
emailInput.current.value = '';

setSubmitState(FeedbackState.SUCCESS);
Expand All @@ -59,29 +54,40 @@ Email: ${emailInput.current.value ?? 'Not provided'}

return (
<Stack spacing="1rem" padding="0.5rem" width="fit-content">
<label htmlFor="nameInput">Name (optional)</label>
<InputField id="nameInput" ref={nameInput} type="text" />
{submitState === FeedbackState.SUCCESS && <Badge>Thank you!</Badge>}

<label htmlFor="emailInput">Email (optional)</label>
<label htmlFor="emailInput" style={{ fontWeight: 'bold' }}>
Email (optional)
</label>
<InputField id="emailInput" ref={emailInput} type="email" />

<label htmlFor="feedbackTextArea">Feedback</label>
<Box
as="textarea"
id="feedbackTextArea"
<label htmlFor="feedbackTextArea" style={{ fontWeight: 'bold' }}>
Feedback
</label>
<TextArea
ref={feedbackTextArea}
resize={'none'}
height="16rem"
width={['15rem', '20rem']}
id="feedbackTextArea"
style={{
resize: 'none',
height: '16rem',
width: '15rem',
}}
placeholder={`The Toilet Map is a free and open source project that we maintain in our spare time.
We'd be so grateful if you could take a moment to give us feedback on how we could make your experience even better.`}
aria-description={`The Toilet Map is a free and open source project that we maintain in our spare time.
We'd be so grateful if you could take a moment to give us feedback on how we could make your experience even better.`}
></Box>
></TextArea>

<Link
target="_blank"
href="/privacy"
style={{ fontSize: 'var(--text--1)' }}
>
Privacy Policy
</Link>

{submitState === FeedbackState.SUCCESS && <Badge>Thank you!</Badge>}
<Button
htmlElement="button"
variant="primary"
Expand Down
27 changes: 22 additions & 5 deletions src/pages/api/feedback/index.page.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,36 @@
import { NextApiRequest, NextApiResponse } from 'next';
import prisma from '../../../api/prisma/prisma';

async function handler(req: NextApiRequest, res: NextApiResponse) {
const feedback = req.body;
const { text, email } = req.body;

if (typeof text !== 'string' || text.length === 0) {
return res.status(400).send('Feedback text is required');
}

try {
// We'd like to record the full feedback entry in our database for future reference.
await prisma.feedback.create({
data: {
email,
feedback_text: text,
},
});

// We only pass on the feedback content to Slack, not the users' email if they provided one.
await fetch(process.env.SLACK_FEEDBACK_WEBHOOK, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ text: feedback?.text }),
body: JSON.stringify({
text: 'Feedback:\r\n${text}',
}),
});
res.send(200);
return res.send(200);
} catch (error) {
console.error('There was an error sending the feedback to Slack', error);
res.send(500);
console.error('There was an error processing the feedback', error);
return res.send(500);
}
}

Expand Down

0 comments on commit 3b17857

Please sign in to comment.