mirror of
https://github.com/formbricks/formbricks.git
synced 2026-01-05 21:32:02 -06:00
fix: survey background image upload issue (#2222)
Co-authored-by: pandeymangg <anshuman.pandey9999@gmail.com>
This commit is contained in:
committed by
GitHub
parent
92d88271d7
commit
65a152e518
@@ -5,7 +5,7 @@ interface AnimatedSurveyBgProps {
|
||||
background: string;
|
||||
}
|
||||
|
||||
export default function AnimatedSurveyBg({ handleBgChange, background }: AnimatedSurveyBgProps) {
|
||||
export const AnimatedSurveyBg = ({ handleBgChange, background }: AnimatedSurveyBgProps) => {
|
||||
const [animation, setAnimation] = useState(background || "/animated-bgs/4K/1_4k.mp4");
|
||||
const [hoveredVideo, setHoveredVideo] = useState<number | null>(null);
|
||||
|
||||
@@ -103,4 +103,4 @@ export default function AnimatedSurveyBg({ handleBgChange, background }: Animate
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,13 +2,13 @@ import { useState } from "react";
|
||||
|
||||
import { ColorPicker } from "@formbricks/ui/ColorPicker";
|
||||
|
||||
interface ColorSurveyBgBgProps {
|
||||
interface ColorSurveyBgProps {
|
||||
handleBgChange: (bg: string, bgType: string) => void;
|
||||
colours: string[];
|
||||
background: string;
|
||||
}
|
||||
|
||||
export default function ColorSurveyBg({ handleBgChange, colours, background }: ColorSurveyBgBgProps) {
|
||||
export const ColorSurveyBg = ({ handleBgChange, colours, background }: ColorSurveyBgProps) => {
|
||||
const [color, setColor] = useState(background || "#ffff");
|
||||
|
||||
const handleBg = (x: string) => {
|
||||
@@ -35,4 +35,4 @@ export default function ColorSurveyBg({ handleBgChange, colours, background }: C
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,23 +1,12 @@
|
||||
import FileInput from "@formbricks/ui/FileInput";
|
||||
|
||||
interface ImageSurveyBgBgProps {
|
||||
interface ImageSurveyBgProps {
|
||||
environmentId: string;
|
||||
handleBgChange: (url: string, bgType: string) => void;
|
||||
background: string;
|
||||
}
|
||||
|
||||
export default function ImageSurveyBg({ environmentId, handleBgChange, background }: ImageSurveyBgBgProps) {
|
||||
const isUrl = (str: string) => {
|
||||
try {
|
||||
new URL(str);
|
||||
return true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const fileUrl = isUrl(background ?? "") ? background ?? "" : "";
|
||||
|
||||
export const ImageSurveyBg = ({ environmentId, handleBgChange, background }: ImageSurveyBgProps) => {
|
||||
return (
|
||||
<div className="mt-2 w-full">
|
||||
<div className="flex w-full items-center justify-center">
|
||||
@@ -32,9 +21,10 @@ export default function ImageSurveyBg({ environmentId, handleBgChange, backgroun
|
||||
handleBgChange("", "image");
|
||||
}
|
||||
}}
|
||||
fileUrl={fileUrl}
|
||||
fileUrl={background}
|
||||
maxSizeInMB={2}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,9 +2,9 @@ import { useEffect, useState } from "react";
|
||||
|
||||
import { TSurvey } from "@formbricks/types/surveys";
|
||||
|
||||
import AnimatedSurveyBg from "./AnimatedSurveyBg";
|
||||
import ColorSurveyBg from "./ColorSurveyBg";
|
||||
import ImageSurveyBg from "./ImageSurveyBg";
|
||||
import { AnimatedSurveyBg } from "./AnimatedSurveyBg";
|
||||
import { ColorSurveyBg } from "./ColorSurveyBg";
|
||||
import { ImageSurveyBg } from "./ImageSurveyBg";
|
||||
|
||||
interface SurveyBgSelectorTabProps {
|
||||
localSurvey: TSurvey;
|
||||
|
||||
@@ -9,7 +9,7 @@ import toast from "react-hot-toast";
|
||||
import { cn } from "@formbricks/lib/cn";
|
||||
import { TAllowedFileExtension } from "@formbricks/types/common";
|
||||
|
||||
import { uploadFile } from "./lib/fileUpload";
|
||||
import { getAllowedFiles, uploadFile } from "./lib/fileUpload";
|
||||
|
||||
const allowedFileTypesForPreview = ["png", "jpeg", "jpg", "webp"];
|
||||
const isImage = (name: string) => {
|
||||
@@ -23,6 +23,7 @@ interface FileInputProps {
|
||||
fileUrl?: string | string[];
|
||||
multiple?: boolean;
|
||||
imageFit?: "cover" | "contain";
|
||||
maxSizeInMB?: number;
|
||||
}
|
||||
|
||||
interface SelectedFile {
|
||||
@@ -39,6 +40,7 @@ const FileInput: React.FC<FileInputProps> = ({
|
||||
fileUrl,
|
||||
multiple = false,
|
||||
imageFit = "cover",
|
||||
maxSizeInMB,
|
||||
}) => {
|
||||
const [selectedFiles, setSelectedFiles] = useState<SelectedFile[]>([]);
|
||||
|
||||
@@ -48,19 +50,9 @@ const FileInput: React.FC<FileInputProps> = ({
|
||||
toast.error("Only one file is allowed");
|
||||
}
|
||||
|
||||
const allowedFiles = files.filter(
|
||||
(file) =>
|
||||
file &&
|
||||
file.type &&
|
||||
allowedFileExtensions.includes(file.name.split(".").pop() as TAllowedFileExtension)
|
||||
);
|
||||
|
||||
if (allowedFiles.length < files.length) {
|
||||
if (allowedFiles.length === 0) {
|
||||
toast.error("No files are supported");
|
||||
return;
|
||||
}
|
||||
toast.error("Some files are not supported");
|
||||
const allowedFiles = getAllowedFiles(files, allowedFileExtensions, maxSizeInMB);
|
||||
if (allowedFiles.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
setSelectedFiles(
|
||||
@@ -85,7 +77,7 @@ const FileInput: React.FC<FileInputProps> = ({
|
||||
const uploadedUrls: string[] = [];
|
||||
uploadedFiles.forEach((file) => {
|
||||
if (file.status === "fulfilled") {
|
||||
uploadedUrls.push(file.value.url);
|
||||
uploadedUrls.push(encodeURI(file.value.url));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -125,21 +117,9 @@ const FileInput: React.FC<FileInputProps> = ({
|
||||
};
|
||||
|
||||
const handleUploadMore = async (files: File[]) => {
|
||||
let filesToUpload: File[] = files;
|
||||
|
||||
const allowedFiles = filesToUpload.filter(
|
||||
(file) =>
|
||||
file &&
|
||||
file.type &&
|
||||
allowedFileExtensions.includes(file.name.split(".").pop() as TAllowedFileExtension)
|
||||
);
|
||||
|
||||
if (allowedFiles.length < filesToUpload.length) {
|
||||
if (allowedFiles.length === 0) {
|
||||
toast.error("No files are supported");
|
||||
return;
|
||||
}
|
||||
toast.error("Some files are not supported");
|
||||
const allowedFiles = getAllowedFiles(files, allowedFileExtensions, maxSizeInMB);
|
||||
if (allowedFiles.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
setSelectedFiles((prevFiles) => [
|
||||
@@ -165,7 +145,7 @@ const FileInput: React.FC<FileInputProps> = ({
|
||||
const uploadedUrls: string[] = [];
|
||||
uploadedFiles.forEach((file) => {
|
||||
if (file.status === "fulfilled") {
|
||||
uploadedUrls.push(file.value.url);
|
||||
uploadedUrls.push(encodeURI(file.value.url));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -199,6 +179,7 @@ const FileInput: React.FC<FileInputProps> = ({
|
||||
src={file.url}
|
||||
alt={file.name}
|
||||
fill
|
||||
sizes="100%"
|
||||
style={{ objectFit: "cover" }}
|
||||
quality={100}
|
||||
className={!file.uploaded ? "opacity-50" : ""}
|
||||
@@ -253,6 +234,7 @@ const FileInput: React.FC<FileInputProps> = ({
|
||||
src={selectedFiles[0].url}
|
||||
alt={selectedFiles[0].name}
|
||||
fill
|
||||
sizes="100%"
|
||||
style={{ objectFit: imageFit }}
|
||||
quality={100}
|
||||
className={!selectedFiles[0].uploaded ? "opacity-50" : ""}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
"use client";
|
||||
|
||||
const uploadFile = async (
|
||||
import { toast } from "react-hot-toast";
|
||||
|
||||
import { TAllowedFileExtension } from "@formbricks/types/common";
|
||||
|
||||
export const uploadFile = async (
|
||||
file: File | Blob,
|
||||
allowedFileExtensions: string[] | undefined,
|
||||
environmentId: string | undefined
|
||||
@@ -93,4 +97,43 @@ const uploadFile = async (
|
||||
}
|
||||
};
|
||||
|
||||
export { uploadFile };
|
||||
export const getAllowedFiles = (
|
||||
files: File[],
|
||||
allowedFileExtensions: string[],
|
||||
maxSizeInMB?: number
|
||||
): File[] => {
|
||||
const sizeExceedFiles: string[] = [];
|
||||
const unsupportedExtensionFiles: string[] = [];
|
||||
|
||||
const allowedFiles = files.filter((file) => {
|
||||
if (!file || !file.type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const extension = file.name.split(".").pop();
|
||||
const fileSizeInMB = file.size / 1000000; // Kb -> Mb
|
||||
|
||||
if (!allowedFileExtensions.includes(extension as TAllowedFileExtension)) {
|
||||
unsupportedExtensionFiles.push(file.name);
|
||||
return false; // Exclude file if extension not allowed
|
||||
} else if (maxSizeInMB && fileSizeInMB > maxSizeInMB) {
|
||||
sizeExceedFiles.push(file.name);
|
||||
return false; // Exclude files larger than the maximum size
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
// Constructing toast messages based on the issues found
|
||||
let toastMessage = "";
|
||||
if (sizeExceedFiles.length > 0) {
|
||||
toastMessage += `Files exceeding size limit (${maxSizeInMB} MB): ${sizeExceedFiles.join(", ")}. `;
|
||||
}
|
||||
if (unsupportedExtensionFiles.length > 0) {
|
||||
toastMessage += `Unsupported file types: ${unsupportedExtensionFiles.join(", ")}.`;
|
||||
}
|
||||
if (toastMessage) {
|
||||
toast.error(toastMessage);
|
||||
}
|
||||
return allowedFiles;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user