fix: File upload issues and tweaks (#2040)

Co-authored-by: Johannes <johannes@formbricks.com>
This commit is contained in:
Dhruwang Jariwala
2024-02-08 21:11:00 +05:30
committed by GitHub
parent 831bf148d8
commit 0bccee23e9
7 changed files with 83 additions and 37 deletions

View File

@@ -110,11 +110,12 @@ export const withEmailTemplate = (content: string) =>
}
a {
color: #00c4b8;
color: #000000;
}
a:hover {
color: #00e6ca;
color: #000000;
}
h1,
h2,
h3,

View File

@@ -1,5 +1,5 @@
import { TResponse } from "@formbricks/types/responses";
import { TSurveyQuestion } from "@formbricks/types/surveys";
import { TSurveyQuestion, TSurveyQuestionType } from "@formbricks/types/surveys";
import {
DEBUG,
@@ -13,6 +13,7 @@ import {
} from "../constants";
import { createInviteToken, createToken, createTokenForLinkSurvey } from "../jwt";
import { getQuestionResponseMapping } from "../responses";
import { getOriginalFileNameFromUrl } from "../storage/utils";
import { getTeamByEnvironmentId } from "../team/service";
import { withEmailTemplate } from "./email-template";
@@ -176,7 +177,7 @@ export const sendResponseFinishedEmail = async (
html: withEmailTemplate(`
<h1>Hey 👋</h1>
<p>Congrats, you received a new response to your survey!
Someone just completed your survey <strong>${survey.name}</strong><br/></p>
Someone just completed your survey <strong>${survey.name}:</strong><br/></p>
<hr/>
@@ -186,7 +187,29 @@ export const sendResponseFinishedEmail = async (
question.answer &&
`<div style="margin-top:1em;">
<p style="margin:0px;">${question.question}</p>
<p style="font-weight: 500; margin:0px; white-space:pre-wrap">${question.answer}</p>
${
question.type === TSurveyQuestionType.FileUpload
? typeof question.answer !== "string" &&
question.answer
.map((answer) => {
return `
<div style="position: relative; display: flex; width: 15rem; flex-direction: column; align-items: center; justify-content: center; border-radius: 0.5rem; background-color: #e2e8f0; color: black; margin-top:8px;">
<div style="margin-top: 1rem; color: black;">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" className="lucide lucide-file">
<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" />
<path d="M14 2v4a2 2 0 0 0 2 2h4" />
</svg>
</div>
<p style="margin-top: 0.5rem; width: 80%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 0 1rem; font-size: 0.875rem; color: black;">
${getOriginalFileNameFromUrl(answer)}
</p>
</div>
`;
})
.join("")
: `<p style="margin:0px; white-space:pre-wrap"><b>${question.answer}</b></p>`
}
</div>`
)
.join("")}
@@ -195,19 +218,12 @@ export const sendResponseFinishedEmail = async (
survey.id
}/responses?utm_source=email_notification&utm_medium=email&utm_content=view_responses_CTA">${responseCount > 1 ? `View ${responseCount - 1} more ${responseCount === 2 ? "response" : "responses"}` : `View survey summary`}</a>
<div class="tooltip">
<p class='brandcolor'><strong>Start a conversation 💡</strong></p>
${
personEmail
? `<p>Hit 'Reply' or reach out manually: ${personEmail}</p>`
: "<p>If you set the email address as an attribute in in-app surveys, you can reply directly to the respondent.</p>"
}
</div>
<hr/>
<p><b>Don't want to get these emails?</b></p>
<div style="margin-top:0.8em; background-color:#f1f5f9; border-radius:8px; padding:0.01em 1.6em; text-align:center; font-size:0.8em; line-height:1.2em;"><p><i>Turn off notifications for <a href="${WEBAPP_URL}/environments/${environmentId}/settings/notifications?type=alert&elementId=${survey.id}">this form</a>. <br/> Turn off notifications for <a href="${WEBAPP_URL}/environments/${environmentId}/settings/notifications?type=unsubscribedTeamIds&elementId=${team?.id}">all newly created forms</a>.</i></p></div>
<div style="margin-top:0.8em; padding:0.01em 1.6em; text-align:center; font-size:0.8em; line-height:1.2em;">
<p><b>Don't want to get these notifications?</b></p>
<p>Turn off notifications for <a href="${WEBAPP_URL}/environments/${environmentId}/settings/notifications?type=alert&elementId=${survey.id}">this form</a>.
<br/> Turn off notifications for <a href="${WEBAPP_URL}/environments/${environmentId}/settings/notifications?type=unsubscribedTeamIds&elementId=${team?.id}">all newly created forms</a>.</p></div>
`),
});
};

View File

@@ -1,18 +1,39 @@
import { TResponse } from "@formbricks/types/responses";
import { TSurveyQuestion } from "@formbricks/types/surveys";
import { TSurveyQuestion, TSurveyQuestionType } from "@formbricks/types/surveys";
export const getQuestionResponseMapping = (
survey: { questions: TSurveyQuestion[] },
response: TResponse
): { question: string; answer: string }[] => {
const questionResponseMapping: { question: string; answer: string }[] = [];
): { question: string; answer: string | string[]; type: TSurveyQuestionType }[] => {
const questionResponseMapping: {
question: string;
answer: string | string[];
type: TSurveyQuestionType;
}[] = [];
for (const question of survey.questions) {
const answer = response.data[question.id];
const getAnswer = () => {
if (!answer) return "";
else {
if (question.type === "fileUpload") {
if (typeof answer === "string") {
return [answer];
} else {
return answer as string[];
// as array
}
} else {
return answer.toString();
}
}
};
questionResponseMapping.push({
question: question.headline,
answer: typeof answer !== "undefined" ? answer.toString() : "",
answer: getAnswer(),
type: question.type,
});
}

View File

@@ -1,14 +1,18 @@
export const getOriginalFileNameFromUrl = (fileURL: string) => {
const fileNameFromURL = new URL(fileURL).pathname.split("/").pop();
const fileExt = fileNameFromURL?.split(".").pop();
const originalFileName = fileNameFromURL?.split("--fid--")[0];
const fileId = fileNameFromURL?.split("--fid--")[1];
try {
const fileNameFromURL = new URL(fileURL).pathname.split("/").pop();
const fileExt = fileNameFromURL?.split(".").pop();
const originalFileName = fileNameFromURL?.split("--fid--")[0];
const fileId = fileNameFromURL?.split("--fid--")[1];
if (!fileId) {
const fileName = originalFileName ? decodeURIComponent(originalFileName || "") : "";
if (!fileId) {
const fileName = originalFileName ? decodeURIComponent(originalFileName || "") : "";
return fileName;
}
const fileName = originalFileName ? decodeURIComponent(`${originalFileName}.${fileExt}` || "") : "";
return fileName;
} catch (error) {
console.error("Error parsing file URL:", error);
}
const fileName = originalFileName ? decodeURIComponent(`${originalFileName}.${fileExt}` || "") : "";
return fileName;
};

View File

@@ -202,8 +202,8 @@ export default function FileInput({
}, [allowMultipleFiles, fileUrls, isUploading]);
return (
<div className="items-left relative mt-3 flex w-full cursor-pointer flex-col justify-center rounded-lg border-2 border-dashed border-slate-300 bg-slate-50 hover:bg-slate-100 dark:border-slate-600 dark:bg-slate-700 dark:hover:border-slate-500 dark:hover:bg-slate-800">
<div>
<div className="items-left relative mt-3 flex w-full cursor-pointer flex-col justify-center rounded-lg border-2 border-dashed border-slate-300 bg-slate-50 hover:cursor-pointer hover:bg-slate-100 dark:border-slate-600 dark:bg-slate-700 dark:hover:border-slate-500 dark:hover:bg-slate-800">
<div className="max-h-[40vh] overflow-auto">
{fileUrls &&
fileUrls?.map((file, index) => {
const fileName = getOriginalFileNameFromUrl(file);
@@ -241,7 +241,9 @@ export default function FileInput({
<path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z" />
<polyline points="14 2 14 8 20 8" />
</svg>
<p className="mt-1 text-sm text-slate-600 dark:text-slate-400">{fileName}</p>
<p className="mt-1 w-full overflow-hidden overflow-ellipsis whitespace-nowrap px-2 text-center text-sm text-slate-600 dark:text-slate-400">
{fileName}
</p>
</div>
</div>
);

View File

@@ -63,7 +63,7 @@ export default function FileUploadQuestion({
}
}
}}
className="w-full">
className="w-full ">
{question.imageUrl && <QuestionImage imgUrl={question.imageUrl} />}
<Headline headline={question.headline} questionId={question.id} required={question.required} />
<Subheader subheader={question.subheader} questionId={question.id} />

View File

@@ -37,7 +37,7 @@ export const FileUploadResponse = ({ selected }: FileUploadResponseProps) => {
<div className="flex flex-col items-center justify-center p-2">
<FileIcon className="h-6 text-slate-500" />
<p className="mt-2 text-sm text-slate-500 dark:text-slate-400">
<p className="mt-2 w-full overflow-hidden overflow-ellipsis whitespace-nowrap px-2 text-sm text-slate-500 dark:text-slate-400">
{selected && typeof selected === "string" && decodeURIComponent(selected).split("/").pop()}
</p>
</div>
@@ -77,9 +77,11 @@ export const FileUploadResponse = ({ selected }: FileUploadResponseProps) => {
</div>
</a>
<div className="flex flex-col items-center justify-center p-2">
<div className="flex flex-col items-center justify-center p-2 text-center">
<FileIcon className="h-6 text-slate-500" />
<p className="mt-2 text-sm text-slate-500 dark:text-slate-400">{fileName}</p>
<p className="mt-2 w-full overflow-hidden overflow-ellipsis whitespace-nowrap px-1 text-sm text-slate-500 dark:text-slate-400">
{fileName}
</p>
</div>
</div>
);