Przyjemny formularz feedback
Elo żelo! Czy zastanawiałeś się kiedyś, jak zrobić formularz feedbacku, który będzie przyjemny dla użytkownika, a jednocześnie szybki w wykonaniu dla ciebie, bez konieczności tworzenia panelu administracyjnego u siebie? W tym poradniku dowiesz się, jak to osiągnąć z wykorzystaniem Twojego ulubionego frameworku Next.js (lub dowolnego innego, nawet zwykłego HTML-a) oraz backendu w postaci Formularzy Google.
Zamysł jest taki, aby stworzyć w pełni własny formularz na swojej stronie, a odpowiedzi przeglądać wygodnie na stronie Formularzy Google lub w Arkuszach Google. Dzięki temu zaoszczędzisz czas na tworzeniu infrastruktury, jednocześnie zachowując pełną kontrolę nad wyglądem i działaniem formularza.
Założenia
Technologie użyte:
- NextJS jako przykład frameworku na frontcie
- Google Forms jako backend z odpowiedziami
- shadcn/ui jako biblioteka komponentów
tl;dr
Wszystko sprowadza się do wysłania formularza POST do Google Forms z odpowiednimi danymi:
<form action="https://docs.google.com/forms/.../formResponse" method="POST"> <input type="text" name="entry.123456789" /> <input type="text" name="entry.987654321" /> <button type="submit">Submit</button></form>
Aczkolwiek zrobimy to w bardziej elegancki sposób z użyciem react-hook-form
i shadcn/ui
oraz zabezpieczeniem, przeciwko spamowaniu.
Let’s gooo 🚀
To są szybkie kroki, dzięki którym stworzysz formularz feedbacku:
-
Stwórz nowy formularz:
Przejdź na stronę Google Forms, stwórz nowy formularz i dodaj swoje pytania.
-
Opublikuj formularz i stwórz arkusz
Następnie opublikuj publicznie swój forms:
- Przycisk “Opublikuj”
- W kategorii respondenci kliknij “Zarządzaj”
- ‘Dostęp ogólny -> Widok respondenta’ zmień z “Politechnika Wrocławska” na “Każda osoba mająca link”
- “Gotowe” -> “Opublikuj”
-
Stwórz połączony arkusz google
Możesz przeglądać również odpowiedzi i łatwo je udostępniać dzięki arkuszom Google. Wystarczy, że po przejściu do zakładki odpowiedzi,
klikniesz zielony przycisk “Link do Arkuszy” -> “Utwórz”: -
Nowy komponent na stronie
Naszedł czas na dodanie formularza do swojej strony. Przejdźmy do Twojego projektu NextJS, stwórzmy nowy client komponent
FeedbackForm.tsx
:FeedbackForm.tsx "use client";import React from "react";export function FeedbackForm() {return <div>Witam</div>;} -
Wymagane dependencies
Do obsługi
<form>
użyjmyreact-hook-form
i komponentu shadcn/uiForm
. Najpierw dodaj ten komponent do projektu:Okno terminala npx shadcn@latest add form -
Schemat
Aby upewnić się, że użytkownik wysyła tylko takie dane, które są wymagane, stwórzmy schemat formularza:
schemas.ts import { z } from "zod";export const FeedbackFormSchema = z.object({email: z.string(),content: z.string(),}); -
Formularz
Następnie dodajmy formularz do naszego komponentu:
FeedbackForm.tsx "use client";import { zodResolver } from "@hookform/resolvers/zod";import React from "react";import { useForm } from "react-hook-form";import type { z } from "zod";import { Button } from "@/components/ui/button";import {Form,FormControl,FormField,FormItem,FormLabel,FormMessage,} from "@/components/ui/form";import { Input } from "@/components/ui/input";import { Textarea } from "@/components/ui/textarea";import { FeedbackFormSchema } from "@/types/schemas";export function FeedbackForm() {const form = useForm<z.infer<typeof FeedbackFormSchema>>({resolver: zodResolver(FeedbackFormSchema),defaultValues: {email: "",content: "",},});async function onSubmit(values: z.infer<typeof FeedbackFormSchema>) {// Do something with the form values}return (<div className="m-10 w-full rounded-md border p-5 sm:max-w-[425px]"><h1 className="text-lg font-semibold">Formularz</h1><Form {...form}><formonSubmit={form.handleSubmit(onSubmit)}className="grid w-full gap-4 py-4 sm:max-w-[425px]"><FormFieldcontrol={form.control}name="email"render={({ field }) => (<FormItem><FormLabel>Adres email</FormLabel><FormControl><Inputplaceholder="123456@student.pwr.edu.pl"{...field}/></FormControl><FormMessage /></FormItem>)}/><FormFieldcontrol={form.control}name="content"render={({ field }) => (<FormItem><FormLabel>Treść</FormLabel><FormControl><Textarea placeholder="Treść zgłoszenia" {...field} /></FormControl><FormMessage /></FormItem>)}/><Button type="submit">Prześlij zgłoszenie</Button></form></Form></div>);}Efekt tego wygląda mniej więcej tak:
-
Backend
Aby cała magia mogła się zadziać, stwórzmy
Server Action
, która będzie wysyłać dane do Google.actions/feedback.ts "use server";import type { z } from "zod";import { env } from "@/env.mjs";import { FeedbackFormSchema } from "@/types/schemas";export const sendFeedbackForm = async (values: z.infer<typeof FeedbackFormSchema>) => {try {FeedbackFormSchema.parse(values);// Jakaś funkcja do sprawdzania rate-limitów, czy użytkownik nie spamuje// const isSpam = await checkSpam(values);// if (isSpam) { return false } czy cośconst googleFormUrl = process.env.FORMS_LINK;const formData = new URLSearchParams();formData.append(process.env.FORMS_email, values.email);formData.append(process.env.FORMS_content, values.content);const response = await fetch(googleFormUrl, {method: "POST",body: formData,headers: {"Content-Type": "application/x-www-form-urlencoded",},});// Obsługa odpowiedziif (response.ok) {return true;} else {console.error("Error while sending feedback form", response);}} catch (error) {console.error("Error while sending feedback form", error);}}; -
Zdobycie potrzebnych danych
Aby uzupełnić .env o potrzebne dane, przejdź do swojego formularza Google i w górnym topbarze po prawej kliknij ikonke oka, czyli podgląd:
Następnie otwórz narzędzia deweloperskie przeglądarki i wybierz zakładkę
Elements
. Następnie inspect toolem (Ctrl + Shift + C
) najedź na formularz i znajdź elementform
:Skopiuj link z
action
i zapisz do zmiennejFORMS_LINK
w env.Następnie wyszukaj
Ctrl + F
w devtoolsach (nie na stronie!)entry.
aby znaleźć dwa pola (jeśli tyle miałeś w formularzu) i skopiuj je do odpowiednich zmiennych. Są one ułożone zwykle w dobrej kolejności:Przykładowy
.env
:.env FORMS_LINK=https://docs.google.com/forms/.../formResponseFORMS_email=entry.123456789FORMS_content=entry.987654321 -
Połączenie formularza z backendem
Na sam koniec zostało połączenie formularza z backendem. Wystarczy dodać
Server Action
do naszego formularza:FeedbackForm.tsx "use client";import { zodResolver } from "@hookform/resolvers/zod";import React from "react";import { useForm } from "react-hook-form";import type { z } from "zod";import { Button } from "@/components/ui/button";import {Form,FormControl,FormField,FormItem,FormLabel,FormMessage,} from "@/components/ui/form";import { Input } from "@/components/ui/input";import { FeedbackFormSchema } from "@/types/schemas";import { sendFeedbackForm } from "@/actions/feedback";export function FeedbackForm() {const form = useForm<z.infer<typeof FeedbackFormSchema>>({resolver: zodResolver(FeedbackFormSchema),defaultValues: {email: "",content: "",},});async function onSubmit(values: z.infer<typeof FeedbackFormSchema>) {await sendFeedbackForm(values);}return (<div className="m-10 w-full rounded-md border p-5 sm:max-w-[425px]"><h1 className="text-lg font-semibold">Formularz</h1><Form {...form}><formonSubmit={form.handleSubmit(onSubmit)}className="grid w-full gap-4 py-4 sm:max-w-[425px]"><FormFieldcontrol={form.control}name="email"render={({ field }) => (<FormItem><FormLabel>Opcja 1</FormLabel><FormControl><Inputplaceholder="np. Błąd związany z formularzem"{...field}/></FormControl><FormMessage /></FormItem>)}/><FormFieldcontrol={form.control}name="content"render={({ field }) => (<FormItem><FormLabel>Opcja 2</FormLabel><FormControl><Inputplaceholder="np. Błąd związany z formularzem"{...field}/></FormControl><FormMessage /></FormItem>)}/><Button type="submit">Prześlij zgłoszenie</Button></form></Form></div>);}
That’s it
Na koniec możesz do tego dodać jakieś ładowanie, komunikaty o sukcesie, błędach, użyć react-query, disable przycisk i pola w czasie wysylania itp. ale to już zależy od Ciebie. Teraz możesz cieszyć się swoim własnym formularzem feedbacku, który jest szybki i przyjemny dla użytkownika.