-
-
Notifications
You must be signed in to change notification settings - Fork 170
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: notes | Func of Paste, Drop Image In editor (#541)
* [Feat] Create new CheckBoxClickable Component why: make the MarkdownEditor Component cleaner how: move relevant code to CheckBoxClickable Component file * [Feat] Add Func of Paste, Drop Image In editor why: so user could paste and drop images in md editor how: integrate the code from CreateBlog * [Feat] Manage the Image Path to be Correct why: so we could also display the Image how: as was done in Feeds page * [Bug] Not Related, Fix AutoComplete Warning In Login Page why: it appers non stop how: set "off" instead of false or null * [Feat] Update The Description Component State When Add Images why: so when the user save the note the images will be added to Description context how: pass the handleChange to useImageUploadEvents and update it * [Feat] Some Tweeks What: 1. change "undescribedNote" to "(Empty)" 2. remove id from "untitledNote" to "untitledNote #number" 3. remove all the address of the image and leave only the name of image how: 1. change when needed 2. make count in redux 3. with regexp why: 1. looks better 2. to not show the id of note to user 3. looks better * [Feat] Some Style Tweaks what: 1. change the title editor , dont need to preview what we input 2. make description and description preview in edit mode scrollable 3. handle text overflow when needed why: better ux how: 1. change styles 2. overflow-y:auto and limit width 3. overflow-wrap:break-word;
- Loading branch information
Showing
16 changed files
with
256 additions
and
79 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
45 changes: 45 additions & 0 deletions
45
src/components/Common/MarkdownEditor/CheckBoxClickable.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import React from "react"; | ||
|
||
const compareStrings = (str1, str2) => { | ||
for (let i = 0, j = 0; i < str1.length || j < str2.length; i++, j++) { | ||
if (i >= str1.length) return false; | ||
if (j >= str2.length) return false; | ||
if (str1[i] !== str2[j]) return false; | ||
} | ||
return true; | ||
}; | ||
const CheckBoxClickable = ({ value, onChangeValue, disabled, ...props }) => { | ||
if (disabled) return <input {...props} disabled={true} />; | ||
|
||
const handleCheckBoxChange = (e) => { | ||
const textOfCheckBox = e.target.parentNode.textContent; | ||
const valueListOfLines = value.split("\n"); | ||
const findCheckedBoxLineIndex = valueListOfLines.findIndex((item) => | ||
compareStrings(item?.replace(/- \[ \]|- \[[^]]+/, ""), textOfCheckBox.split("\n")[0]), | ||
); | ||
valueListOfLines[findCheckedBoxLineIndex] = valueListOfLines[findCheckedBoxLineIndex].replace( | ||
/- \[ \]|- \[[^]]+/, | ||
(match) => (match === "- [ ]" ? "- [X]" : "- [ ]"), | ||
); | ||
onChangeValue(valueListOfLines.join("\n")); | ||
}; | ||
|
||
return ( | ||
<input | ||
{...props} | ||
disabled={false} | ||
onChange={(e) => { | ||
if (props.type === "checkbox") { | ||
const isChecked = e.target.hasAttribute("checked"); | ||
handleCheckBoxChange(e); | ||
if (isChecked) { | ||
e.target.removeAttribute("checked"); | ||
} else { | ||
e.target.setAttribute("checked", "checked"); | ||
} | ||
} | ||
}} | ||
/> | ||
); | ||
}; | ||
export default CheckBoxClickable; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
99 changes: 99 additions & 0 deletions
99
src/components/Common/MarkdownEditor/useImageUploadEvents.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import { useState } from "react"; | ||
import axios from "axios"; | ||
import { cdnContentImagesUrl, getApiUrl } from "../../../features/apiUrl"; | ||
import { toast } from "react-toastify"; | ||
|
||
const useImageUploadEvents = (prevContent, setContent, pageName) => { | ||
const [errorMessage, setErrorMessage] = useState(""); | ||
|
||
const handleUploadAndDisplayImage = async (file) => { | ||
const fileName = `${pageName}-${Date.now()}.${file && file.type.split("/")[1]}`; | ||
const reader = new FileReader(); | ||
reader.onloadend = async () => { | ||
const newFile = new File([reader.result], fileName, { type: file && file.type }); | ||
const formData = new FormData(); | ||
formData.append("image", newFile); | ||
console.log(newFile); | ||
const API_URL = getApiUrl("api/upload"); | ||
await axios.post(API_URL, formData); | ||
const newImageUrl = cdnContentImagesUrl(`/${pageName}/${fileName.split("-")[1]}`); | ||
setContent(prevContent + `\n![PLEASE_ADD_A_NAME_FOR_THIS_IMAGE_HERE](${newImageUrl})`); | ||
}; | ||
reader.readAsArrayBuffer(file); | ||
}; | ||
|
||
const handleDrop = async (e) => { | ||
e.preventDefault(); | ||
const file = e.dataTransfer.files[0]; | ||
if (!file) return; | ||
if (!file.type.startsWith("image/")) { | ||
toast.error("Invalid file type. Only images are allowed."); | ||
return; | ||
} | ||
const allowedTypes = ["image/png", "image/jpeg", "image/jpg"]; | ||
|
||
if (!allowedTypes.includes(file.type)) { | ||
toast.error("Invalid file type. Only png and jpg are allowed."); | ||
return; | ||
} | ||
const maxFileSize = 1000000; // 1000KB | ||
if (file.size > maxFileSize) { | ||
toast.error(`File size should be less than ${maxFileSize / 1000}KB.`); | ||
return; | ||
} | ||
try { | ||
handleUploadAndDisplayImage(file); | ||
} catch (err) { | ||
if (err.message === "Request failed with status code 429") { | ||
setErrorMessage("You are uploading images too fast. Please wait a few seconds and try again."); | ||
errorMessage && toast.error(errorMessage); | ||
if (errorMessage === "") { | ||
toast("You are uploading images too fast. Please wait a few seconds and try again."); | ||
} | ||
} | ||
} | ||
}; | ||
const handlePaste = async (e) => { | ||
const items = (e.clipboardData || e.originalEvent.clipboardData).items; | ||
let file = null; | ||
|
||
// Check if the paste event contains an image | ||
for (const item of items) { | ||
if (item.type.startsWith("image")) { | ||
file = item.getAsFile(); | ||
break; | ||
} | ||
} | ||
if (!file) return; | ||
if (!file.type.startsWith("image/")) { | ||
toast.error("Invalid file type. Only images are allowed."); | ||
return; | ||
} | ||
if (file.type !== ("image/png" || "image/jpeg" || "image/jpg")) { | ||
toast.error("Invalid file type. Only png and jpg are allowed."); | ||
return; | ||
} | ||
const maxFileSize = 1000000; // 1000KB | ||
if (file.size > maxFileSize) { | ||
toast.error(`File size should be less than ${maxFileSize / 1000}KB.`); | ||
return; | ||
} | ||
try { | ||
handleUploadAndDisplayImage(file); | ||
} catch (err) { | ||
if (err.message === "Request failed with status code 429") { | ||
setErrorMessage("You are uploading images too fast. Please wait a few seconds and try again."); | ||
errorMessage && toast.error(errorMessage); | ||
if (errorMessage === "") { | ||
toast("You are uploading images too fast. Please wait a few seconds and try again."); | ||
} | ||
} | ||
} | ||
}; | ||
const handleDragOver = (e) => { | ||
e.preventDefault(); | ||
}; | ||
|
||
return { onDropImage: handleDrop, onDragOverImage: handleDragOver, onPasteImage: handlePaste }; | ||
}; | ||
export default useImageUploadEvents; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.