From c4f0c69fd3893c961bd941654e74a4abab9644c8 Mon Sep 17 00:00:00 2001 From: keraliss Date: Tue, 19 Nov 2024 12:34:38 +0530 Subject: [PATCH 1/7] add image in markdown format --- .../components/AnswerSettings/UploadImage.tsx | 96 +++++++++++++++++++ .../components/AnswerSettings/index.tsx | 17 ++++ 2 files changed, 113 insertions(+) create mode 100644 packages/formstr-app/src/containers/CreateFormNew/components/AnswerSettings/UploadImage.tsx diff --git a/packages/formstr-app/src/containers/CreateFormNew/components/AnswerSettings/UploadImage.tsx b/packages/formstr-app/src/containers/CreateFormNew/components/AnswerSettings/UploadImage.tsx new file mode 100644 index 0000000..ff93f83 --- /dev/null +++ b/packages/formstr-app/src/containers/CreateFormNew/components/AnswerSettings/UploadImage.tsx @@ -0,0 +1,96 @@ +import { UploadOutlined } from "@ant-design/icons"; +import { Button } from "antd"; +import React, { useState, ChangeEvent } from "react"; + +interface Props { + onImageUpload?: (url: string) => void; +} + +const UploadImage: React.FC = ({ onImageUpload }) => { + const [uploading, setUploading] = useState(false); + const [imageUrl, setImageUrl] = useState(""); + const fileInputRef = React.useRef(null); + + const handleButtonClick = () => { + fileInputRef.current?.click(); + }; + + const handleFileSelect = async (e: ChangeEvent) => { + const file = e.target.files?.[0]; + if (!file) return; + handleUpload(file); + }; + + const handleUpload = async (file: File) => { + try { + setUploading(true); + + const formData = new FormData(); + formData.append("image", file); + + const response = await fetch( + "https://api.imgbb.com/1/upload?key=47b2691c6dca3f52bf6f70029396682d", + { + method: "POST", + body: formData, + } + ); + + if (!response.ok) { + throw new Error(`Upload failed: ${response.statusText}`); + } + + const result = await response.json(); + if (result.data?.display_url) { + const url = result.data.display_url; + const fileName = file.name.replace(/\.[^/.]+$/, ''); + const markdownFormat = `[${fileName}](${url})`; + onImageUpload?.(markdownFormat); + } + } catch (error) { + console.error("Error uploading image:", error); + alert("Upload failed. Please try again."); + } finally { + setUploading(false); + } + }; + + return ( +
+ {/* Hidden file input */} + + + {/* Ant Design Button that triggers the file input */} + + + {imageUrl && Uploaded} +
+ ); +}; + +export default UploadImage; diff --git a/packages/formstr-app/src/containers/CreateFormNew/components/AnswerSettings/index.tsx b/packages/formstr-app/src/containers/CreateFormNew/components/AnswerSettings/index.tsx index 365773a..d69b2cd 100644 --- a/packages/formstr-app/src/containers/CreateFormNew/components/AnswerSettings/index.tsx +++ b/packages/formstr-app/src/containers/CreateFormNew/components/AnswerSettings/index.tsx @@ -7,6 +7,8 @@ import StyleWrapper from "./style"; import { RightAnswer } from "./RightAnswer"; import { Field } from "../../providers/FormBuilder"; import { IAnswerSettings } from "./types"; +import UploadImage from "./UploadImage"; +import { useState } from "react"; const { Text } = Typography; @@ -32,6 +34,8 @@ function AnswerSettings() { option.answerSettings.renderElement === answerSettings.renderElement ); + const [imageUrl, setImageUrl] = useState(""); + const handleRightAnswer = (rightAnswer: string) => { const field = question; let newAnswerSettings = { @@ -68,12 +72,25 @@ function AnswerSettings() { editQuestion(field, field[1]); }; + const handleImageUpload = (markdownUrl: string) => { + console.log('Received markdown URL:', markdownUrl); + setImageUrl(markdownUrl); + let field = question; + let newAnswerSettings = { + ...answerSettings, + imageUrl: markdownUrl + }; + field[5] = JSON.stringify(newAnswerSettings); + editQuestion(field, field[1]); + }; + return ( Question {questionIndex + 1} of {questionsList.length} +
Properties
From 8879474d9a0dc5995416255d600be905af3da2f2 Mon Sep 17 00:00:00 2001 From: keraliss Date: Wed, 20 Nov 2024 21:05:35 +0530 Subject: [PATCH 2/7] add modal and image url --- .../components/AnswerSettings/UploadImage.tsx | 154 ++++++++++++++---- .../components/AnswerSettings/index.tsx | 25 ++- 2 files changed, 138 insertions(+), 41 deletions(-) diff --git a/packages/formstr-app/src/containers/CreateFormNew/components/AnswerSettings/UploadImage.tsx b/packages/formstr-app/src/containers/CreateFormNew/components/AnswerSettings/UploadImage.tsx index ff93f83..1c05abb 100644 --- a/packages/formstr-app/src/containers/CreateFormNew/components/AnswerSettings/UploadImage.tsx +++ b/packages/formstr-app/src/containers/CreateFormNew/components/AnswerSettings/UploadImage.tsx @@ -1,6 +1,6 @@ import { UploadOutlined } from "@ant-design/icons"; -import { Button } from "antd"; -import React, { useState, ChangeEvent } from "react"; +import { Button, Modal, Input, Tabs } from "antd"; +import React, { useState, ChangeEvent, useRef } from "react"; interface Props { onImageUpload?: (url: string) => void; @@ -9,12 +9,37 @@ interface Props { const UploadImage: React.FC = ({ onImageUpload }) => { const [uploading, setUploading] = useState(false); const [imageUrl, setImageUrl] = useState(""); - const fileInputRef = React.useRef(null); + const [urlInput, setUrlInput] = useState(""); + const [isModalOpen, setIsModalOpen] = useState(false); + const fileInputRef = useRef(null); + const modalRef = useRef(null); + + const formatImageUrl = (url: string, customName?: string) => { + const fileName = customName || url.split('/').pop()?.replace(/\.[^/.]+$/, '') || 'image'; + return `[${fileName}](${url})`; + }; + + const showModal = () => { + setIsModalOpen(true); + }; + + const handleCancel = () => { + setIsModalOpen(false); + setUrlInput(""); + }; const handleButtonClick = () => { fileInputRef.current?.click(); }; + const handleUrlSubmit = () => { + if (urlInput) { + onImageUpload?.(formatImageUrl(urlInput)); + setIsModalOpen(false); + setUrlInput(""); + } + }; + const handleFileSelect = async (e: ChangeEvent) => { const file = e.target.files?.[0]; if (!file) return; @@ -24,7 +49,6 @@ const UploadImage: React.FC = ({ onImageUpload }) => { const handleUpload = async (file: File) => { try { setUploading(true); - const formData = new FormData(); formData.append("image", file); @@ -42,10 +66,8 @@ const UploadImage: React.FC = ({ onImageUpload }) => { const result = await response.json(); if (result.data?.display_url) { - const url = result.data.display_url; - const fileName = file.name.replace(/\.[^/.]+$/, ''); - const markdownFormat = `[${fileName}](${url})`; - onImageUpload?.(markdownFormat); + onImageUpload?.(formatImageUrl(result.data.display_url, file.name)); + setIsModalOpen(false); } } catch (error) { console.error("Error uploading image:", error); @@ -55,42 +77,108 @@ const UploadImage: React.FC = ({ onImageUpload }) => { } }; + const items = [ + { + key: '1', + label: 'Upload Image', + children: ( +
+ + +
+ ), + }, + { + key: '2', + label: 'Image URL', + children: ( +
+ setUrlInput(e.target.value)} + style={{ marginBottom: 16 }} + rows={4} + aria-label="Image URL input" + /> + +
+ ), + }, + ]; + return (
- {/* Hidden file input */} - - - {/* Ant Design Button that triggers the file input */} - {imageUrl && Uploaded} + ( +
+ {modal} +
+ )} + > + +
+ + {imageUrl && ( + Uploaded + )}
); }; -export default UploadImage; +export default UploadImage; \ No newline at end of file diff --git a/packages/formstr-app/src/containers/CreateFormNew/components/AnswerSettings/index.tsx b/packages/formstr-app/src/containers/CreateFormNew/components/AnswerSettings/index.tsx index d69b2cd..3c0435a 100644 --- a/packages/formstr-app/src/containers/CreateFormNew/components/AnswerSettings/index.tsx +++ b/packages/formstr-app/src/containers/CreateFormNew/components/AnswerSettings/index.tsx @@ -73,14 +73,23 @@ function AnswerSettings() { }; const handleImageUpload = (markdownUrl: string) => { - console.log('Received markdown URL:', markdownUrl); - setImageUrl(markdownUrl); - let field = question; - let newAnswerSettings = { - ...answerSettings, - imageUrl: markdownUrl - }; - field[5] = JSON.stringify(newAnswerSettings); + // Extract name and url from [name](url) format + const name = markdownUrl.match(/\[(.*?)\]/)?.[1] || ''; + const url = markdownUrl.match(/\((.*?)\)/)?.[1] || ''; + const imageMarkdown = `![${name}](${url})`; + + const field: Field = [ + question[0], + question[1], + question[2], + imageMarkdown, // Store full markdown in display field + question[4], + JSON.stringify({ + ...answerSettings, + imageUrl: imageMarkdown + }) + ]; + editQuestion(field, field[1]); }; From ae48a6c2c7e73c7a27e7d17b3e60e6e550fc9f66 Mon Sep 17 00:00:00 2001 From: keraliss Date: Fri, 22 Nov 2024 13:12:59 +0530 Subject: [PATCH 3/7] upload multiple image and live change of the text field --- .../components/AnswerSettings/UploadImage.tsx | 2 +- .../components/AnswerSettings/index.tsx | 46 ++++++++++++++----- .../components/QuestionCard/index.tsx | 3 +- 3 files changed, 38 insertions(+), 13 deletions(-) diff --git a/packages/formstr-app/src/containers/CreateFormNew/components/AnswerSettings/UploadImage.tsx b/packages/formstr-app/src/containers/CreateFormNew/components/AnswerSettings/UploadImage.tsx index 1c05abb..dd52fdf 100644 --- a/packages/formstr-app/src/containers/CreateFormNew/components/AnswerSettings/UploadImage.tsx +++ b/packages/formstr-app/src/containers/CreateFormNew/components/AnswerSettings/UploadImage.tsx @@ -174,7 +174,7 @@ const UploadImage: React.FC = ({ onImageUpload }) => { Uploaded )}
diff --git a/packages/formstr-app/src/containers/CreateFormNew/components/AnswerSettings/index.tsx b/packages/formstr-app/src/containers/CreateFormNew/components/AnswerSettings/index.tsx index 3c0435a..0afbd7c 100644 --- a/packages/formstr-app/src/containers/CreateFormNew/components/AnswerSettings/index.tsx +++ b/packages/formstr-app/src/containers/CreateFormNew/components/AnswerSettings/index.tsx @@ -8,7 +8,7 @@ import { RightAnswer } from "./RightAnswer"; import { Field } from "../../providers/FormBuilder"; import { IAnswerSettings } from "./types"; import UploadImage from "./UploadImage"; -import { useState } from "react"; +import { useState, useEffect } from "react"; const { Text } = Typography; @@ -34,7 +34,16 @@ function AnswerSettings() { option.answerSettings.renderElement === answerSettings.renderElement ); - const [imageUrl, setImageUrl] = useState(""); + const [uploadedImages, setUploadedImages] = useState>(() => { + const saved = localStorage.getItem(`uploadedImages_${questionIdInFocus}`); + return saved ? JSON.parse(saved) : []; + }); + + useEffect(() => { + if (answerSettings.uploadedImages) { + setUploadedImages(answerSettings.uploadedImages); + } + }, [questionIdInFocus]); const handleRightAnswer = (rightAnswer: string) => { const field = question; @@ -73,26 +82,41 @@ function AnswerSettings() { }; const handleImageUpload = (markdownUrl: string) => { - // Extract name and url from [name](url) format const name = markdownUrl.match(/\[(.*?)\]/)?.[1] || ''; const url = markdownUrl.match(/\((.*?)\)/)?.[1] || ''; const imageMarkdown = `![${name}](${url})`; + + const newImages = [...uploadedImages, { name, url }]; + setUploadedImages(newImages); + localStorage.setItem(`uploadedImages_${questionIdInFocus}`, JSON.stringify(newImages)); + + const existingConfig = JSON.parse(question[5] || '{}'); + const existingText = question[3] || ''; + let newDisplay = existingText; + if (existingText && !existingText.endsWith('\n\n')) { + newDisplay += '\n\n'; + } + newDisplay += imageMarkdown; + const field: Field = [ question[0], - question[1], + question[1], question[2], - imageMarkdown, // Store full markdown in display field + newDisplay.trim(), question[4], JSON.stringify({ - ...answerSettings, - imageUrl: imageMarkdown + ...existingConfig, + imageUrl: imageMarkdown, + uploadedImages: newImages, + displayImages: true, + text: existingText }) - ]; - - editQuestion(field, field[1]); - }; + ]; + editQuestion(field, field[1]); + }; + return ( diff --git a/packages/formstr-app/src/containers/CreateFormNew/components/QuestionCard/index.tsx b/packages/formstr-app/src/containers/CreateFormNew/components/QuestionCard/index.tsx index 215bb2d..6681b1b 100644 --- a/packages/formstr-app/src/containers/CreateFormNew/components/QuestionCard/index.tsx +++ b/packages/formstr-app/src/containers/CreateFormNew/components/QuestionCard/index.tsx @@ -81,9 +81,10 @@ const QuestionCard: React.FC = ({