mirror of
https://github.com/formbricks/formbricks.git
synced 2026-05-08 02:43:06 -05:00
feat: added qr code feature (#4951)
This commit is contained in:
+2
@@ -16,6 +16,7 @@ interface LinkTabProps {
|
||||
|
||||
export const LinkTab = ({ survey, webAppUrl, surveyUrl, setSurveyUrl, locale }: LinkTabProps) => {
|
||||
const { t } = useTranslate();
|
||||
|
||||
const docsLinks = [
|
||||
{
|
||||
title: t("environments.surveys.summary.data_prefilling"),
|
||||
@@ -48,6 +49,7 @@ export const LinkTab = ({ survey, webAppUrl, surveyUrl, setSurveyUrl, locale }:
|
||||
locale={locale}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap justify-between gap-2">
|
||||
<p className="pt-2 font-semibold text-slate-700">
|
||||
{t("environments.surveys.summary.you_can_do_a_lot_more_with_links_surveys")} 💡
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
import { Options } from "qr-code-styling";
|
||||
|
||||
export const getQRCodeOptions = (width: number, height: number): Options => ({
|
||||
width,
|
||||
height,
|
||||
type: "svg",
|
||||
data: "",
|
||||
margin: 0,
|
||||
qrOptions: {
|
||||
typeNumber: 0,
|
||||
mode: "Byte",
|
||||
errorCorrectionLevel: "L",
|
||||
},
|
||||
imageOptions: {
|
||||
saveAsBlob: true,
|
||||
hideBackgroundDots: false,
|
||||
imageSize: 0,
|
||||
margin: 0,
|
||||
},
|
||||
dotsOptions: {
|
||||
type: "extra-rounded",
|
||||
color: "#000000",
|
||||
roundSize: true,
|
||||
},
|
||||
backgroundOptions: {
|
||||
color: "#ffffff",
|
||||
},
|
||||
cornersSquareOptions: {
|
||||
type: "dot",
|
||||
color: "#000000",
|
||||
},
|
||||
cornersDotOptions: {
|
||||
type: "dot",
|
||||
color: "#000000",
|
||||
},
|
||||
});
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
"use client";
|
||||
|
||||
import { getQRCodeOptions } from "@/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/lib/get-qr-code-options";
|
||||
import { useTranslate } from "@tolgee/react";
|
||||
import QRCodeStyling from "qr-code-styling";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { toast } from "react-hot-toast";
|
||||
|
||||
export const useSurveyQRCode = (surveyUrl: string) => {
|
||||
const qrCodeRef = useRef<HTMLDivElement>(null);
|
||||
const qrInstance = useRef<QRCodeStyling | null>(null);
|
||||
const { t } = useTranslate();
|
||||
|
||||
useEffect(() => {
|
||||
try {
|
||||
if (!qrInstance.current) {
|
||||
qrInstance.current = new QRCodeStyling(getQRCodeOptions(70, 70));
|
||||
}
|
||||
|
||||
if (surveyUrl && qrInstance.current) {
|
||||
qrInstance.current.update({ data: surveyUrl });
|
||||
|
||||
if (qrCodeRef.current) {
|
||||
qrCodeRef.current.innerHTML = "";
|
||||
qrInstance.current.append(qrCodeRef.current);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
toast.error(t("environments.surveys.summary.failed_to_generate_qr_code"));
|
||||
}
|
||||
}, [surveyUrl]);
|
||||
|
||||
const downloadQRCode = () => {
|
||||
try {
|
||||
const downloadInstance = new QRCodeStyling(getQRCodeOptions(500, 500));
|
||||
downloadInstance.update({ data: surveyUrl });
|
||||
downloadInstance.download({ name: "survey-qr", extension: "png" });
|
||||
} catch (error) {
|
||||
toast.error(t("environments.surveys.summary.failed_to_generate_qr_code"));
|
||||
}
|
||||
};
|
||||
|
||||
return { qrCodeRef, downloadQRCode };
|
||||
};
|
||||
@@ -1,10 +1,11 @@
|
||||
"use client";
|
||||
|
||||
import { useSurveyQRCode } from "@/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/lib/survey-qr-code";
|
||||
import { getFormattedErrorMessage } from "@/lib/utils/helper";
|
||||
import { generateSingleUseIdAction } from "@/modules/survey/list/actions";
|
||||
import { Button } from "@/modules/ui/components/button";
|
||||
import { useTranslate } from "@tolgee/react";
|
||||
import { Copy, RefreshCcw, SquareArrowOutUpRight } from "lucide-react";
|
||||
import { Copy, QrCode, RefreshCcw, SquareArrowOutUpRight } from "lucide-react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { toast } from "react-hot-toast";
|
||||
import { TSurvey } from "@formbricks/types/surveys/types";
|
||||
@@ -68,6 +69,8 @@ export const ShareSurveyLink = ({
|
||||
getUrl();
|
||||
}, [survey, getUrl, language]);
|
||||
|
||||
const { downloadQRCode } = useSurveyQRCode(surveyUrl);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`flex max-w-full flex-col items-center justify-center space-x-2 ${survey.singleUse?.enabled ? "flex-col" : "lg:flex-row"}`}>
|
||||
@@ -100,6 +103,14 @@ export const ShareSurveyLink = ({
|
||||
{t("common.copy")}
|
||||
<Copy />
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
title={t("environments.surveys.summary.download_qr_code")}
|
||||
aria-label={t("environments.surveys.summary.download_qr_code")}
|
||||
size={"icon"}
|
||||
onClick={downloadQRCode}>
|
||||
<QrCode style={{ width: "24px", height: "24px" }} />
|
||||
</Button>
|
||||
{survey.singleUse?.enabled && (
|
||||
<Button
|
||||
title="Regenerate single use survey link"
|
||||
|
||||
@@ -115,6 +115,7 @@
|
||||
"papaparse": "5.4.1",
|
||||
"posthog-js": "1.200.2",
|
||||
"prismjs": "1.30.0",
|
||||
"qr-code-styling": "1.9.1",
|
||||
"react": "19.0.0",
|
||||
"react-colorful": "5.6.1",
|
||||
"react-confetti": "6.1.0",
|
||||
|
||||
Reference in New Issue
Block a user