From d18cba264ebd4058274afbd8609782ced5782308 Mon Sep 17 00:00:00 2001 From: Arya Date: Sat, 21 Oct 2023 13:03:21 +0530 Subject: [PATCH] added lazy loading --- components/core/CreateShape.js | 681 +++++++++++++-------------------- 1 file changed, 271 insertions(+), 410 deletions(-) diff --git a/components/core/CreateShape.js b/components/core/CreateShape.js index 6be3752..3ed2bf0 100644 --- a/components/core/CreateShape.js +++ b/components/core/CreateShape.js @@ -1,436 +1,297 @@ -import React, { useState, useEffect } from "react"; - -// axios +import React, { useState, useEffect, useRef } from "react"; import axios from "axios"; - -// Bootstrap -import Container from "react-bootstrap/Container"; -import Row from "react-bootstrap/Row"; -import Col from "react-bootstrap/Col"; -import Modal from "react-bootstrap/Modal"; -import Button from "react-bootstrap/Button"; - -// ShapeForm and ShapePreview Components +import { Container, Row, Col, Modal, Button } from "react-bootstrap"; import { ShapeForm, ShapePreview } from ".."; - -// Toast import toast from "react-hot-toast"; - -// shapecalculation functions -import { - generateNewVerticeCoordinates, - generateNewFormula, - handleFormulaChange, - calculateRadiusAndFormulaFromMovement, - separateXYValueIntoObject, +import { + generateNewVerticeCoordinates, + generateNewFormula, + handleFormulaChange, + calculateRadiusAndFormulaFromMovement, + separateXYValueIntoObject, } from "../../utils/shape-calculations.js"; - -// shapecalculation data -import { initialState, polygonInitialState, circleInitialState, ellipseInitialState } from "../../utils/shape-initial-data.js"; +import { + initialState, + polygonInitialState, + circleInitialState, + ellipseInitialState, +} from "../../utils/shape-initial-data.js"; const CreateShape = (props) => { + const [shapes, setShapes] = useState([]); + const [shapeInformation, setShapeInformation] = useState({ ...initialState }); + const [loading, setLoading] = useState(false); + const [page, setPage] = useState(1); + const [hasMore, setHasMore] = useState(true); - // shapeInformation holds all information about the shape - const [shapeInformation, setShapeInformation] = useState({ - ...initialState, + const loadMoreRef = useRef(); + + useEffect(() => { + if (props.edit) { + loadShapeForEdit(props.shape); + } + loadShapes(); + }, []); + + const loadShapeForEdit = (shapeToEdit) => { + setShapeInformation({ + name: shapeToEdit.name, + formula: shapeToEdit.formula, + vertices: shapeInformation.vertices, + visibility: shapeInformation.private, + edges: shapeInformation.edges, + notes: shapeInformation.notes, + type: shapeInformation.clipPathType, + backgroundColor: shapeInformation.backgroundColor, + createdBy: props.user.email, + likes: 0 }); + }; + + const loadShapes = async () => { + if (loading) return; + + setLoading(true); + + try { + const response = await axios.get(`/api/shapes?page=${page}`); + const newShapes = response.data.shapes; + + if (newShapes.length === 0) { + setHasMore(false); + } else { + setShapes((prevShapes) => [...prevShapes, ...newShapes]); + setPage(page + 1); + } + } catch (error) { + console.error("Error loading shapes: ", error); + } finally { + setLoading(false); + } + }; + + const handleChange = (event, data, number, type) => { + const name = event.target.name || event.type; + const value = event.target.type === "checkbox" ? event.target.checked : event.target.value; + + if (name === "name") { + setShapeInformation({ + ...shapeInformation, + name: value, + }); + return; + } - // Checks if edit is true and will provide different initial values - useEffect(() => { - - if (props.edit) { - let formula = props.shape.formula; - let slicedFormula = formula.slice(formula.indexOf("(") + 1, formula.indexOf(")")); - let newVerticeCoordinates = []; - let width = "0%"; - let height = "0%"; - - if (!formula.includes("()")) { - - if (props.shape.type === "polygon") { - newVerticeCoordinates = slicedFormula.split(","); - newVerticeCoordinates = newVerticeCoordinates.map((value) => { - return separateXYValueIntoObject(value.trim()); - }); - } - - if (props.shape.type === "circle" && formula.includes("at")) { - let splitFormula = slicedFormula.split("at"); - - width = splitFormula[0].trim(); - - newVerticeCoordinates = [separateXYValueIntoObject(splitFormula[1].trim())]; - } - - if (props.shape.type === "ellipse" && formula.includes("at")) { - let splitFormula = slicedFormula.split("at"); - let widthHeightValues = separateXYValueIntoObject(splitFormula[0].trim()); - - width = widthHeightValues[0]; - height = widthHeightValues[1]; - - newVerticeCoordinates = [separateXYValueIntoObject(splitFormula[1].trim())]; - } - - } - - setShapeInformation({ - ...shapeInformation, - "name": props.shape.name, - "formula": props.shape.formula, - "vertices": props.shape.vertices, - "private": props.shape.private, - "edges": props.shape.edges, - "notes": props.shape.notes, - "clipPathType": props.shape.type, - "backgroundColor": props.shape.backgroundColor, - "verticeCoordinates" : newVerticeCoordinates, - "width": width, - "height": height, - }); - } + if (name === "formula") { + const edgeVerticeNumber = shapeInformation.clipPathType === "polygon" && value !== "" ? value.split(",").length : 0; + + if (value === "") { + handleFormulaChange(`${shapeInformation.clipPathType}()`, edgeVerticeNumber, setShapeInformation); + } else if (value.includes("polygon")) { + handleFormulaChange(value, edgeVerticeNumber, setShapeInformation, "polygon"); + } else if (value.includes("circle")) { + handleFormulaChange(value, edgeVerticeNumber, setShapeInformation, "circle"); + } else if (value.includes("ellipse")) { + handleFormulaChange(value, edgeVerticeNumber, setShapeInformation, "ellipse"); + } else { + handleFormulaChange(value, edgeVerticeNumber, setShapeInformation); + } + return; + } - }, [props.show]); - - // Changes shapeInformation when something in ShapeForm or ShapePreview is altered - const handleChange = (event, data, number, type) => { - - const name = event.target.name || event.type; - const value = event.target.type === "checkbox" ? event.target.checked : event.target.value; - - // Handles name changes - if (name === "name") { - setShapeInformation({ - ...shapeInformation, - "name": value, - }); - return; - } - - // If formula value is changed, alter formula value and verticeCoordinates value depending on clipPathType - if (name === "formula") { - - const edgeVerticeNumber = shapeInformation.clipPathType === "polygon" && value !== "" ? value.split(",").length: 0; - - // If user deletes all, set formula to the Clip-Path type with an empty set of parentheses - if (value === "") { - handleFormulaChange(`${shapeInformation.clipPathType}()`, edgeVerticeNumber, setShapeInformation); - } else if (value.includes("polygon")) { - handleFormulaChange(value, edgeVerticeNumber, setShapeInformation, "polygon"); - } else if (value.includes("circle")) { - handleFormulaChange(value, edgeVerticeNumber, setShapeInformation, "circle"); - } else if (value.includes("ellipse")) { - handleFormulaChange(value, edgeVerticeNumber, setShapeInformation, "ellipse"); - } else { - handleFormulaChange(value, edgeVerticeNumber, setShapeInformation); - } - return; + if (name === "clipPathType") { + if (value === "polygon") { + setShapeInformation({ + ...shapeInformation, + ...polygonInitialState, + }); + } - } - - // If Clip-Path Type is changed, change the value of the clipPathType - if (name === "clipPathType") { - - if (value === "polygon") { - setShapeInformation({ - ...shapeInformation, - ...polygonInitialState, - }); - } - - if (value === "circle") { - setShapeInformation({ - ...shapeInformation, - ...circleInitialState, - }); - } - - if (value === "ellipse") { - setShapeInformation({ - ...shapeInformation, - ...ellipseInitialState, - }); - } - - setShapeInformation(prevState => { - return { - ...prevState, - "clipPathType": value, - "edges": value === "polygon" ? 4 : 0, - "vertices": value === "polygon" ? 4 : 0, - } - }); - return; - } - - // If DraggableVertice is moved, adjust verticeCoordinates and formula - if (name === "mousemove" || name === "touchmove") { - - if (type === "width") { - const newFormulaValues = calculateRadiusAndFormulaFromMovement( - shapeInformation.verticeCoordinates[0].x, - shapeInformation.width, - shapeInformation.height, - data.x - ); - - let newFormula; - - if (shapeInformation.clipPathType === "circle") { - newFormula = `${shapeInformation.clipPathType}(${newFormulaValues.absoluteValueRadius} at ${shapeInformation.verticeCoordinates[0].x} ${shapeInformation.verticeCoordinates[0].y})`; - } else if (shapeInformation.clipPathType === "ellipse") { - newFormula = `${shapeInformation.clipPathType}(${newFormulaValues.absoluteValueRadius} ${newFormulaValues.absoluteValueAxis} at ${shapeInformation.verticeCoordinates[0].x} ${shapeInformation.verticeCoordinates[0].y})`; - } - - setShapeInformation({ - ...shapeInformation, - "width": newFormulaValues.radius, - "formula": newFormula, - }); - - } else if (type === "height") { - const newFormulaValues = calculateRadiusAndFormulaFromMovement( - shapeInformation.verticeCoordinates[0].y, - shapeInformation.height, - shapeInformation.width, - data.y - ); - - let newFormula; - - if (shapeInformation.clipPathType === "ellipse") { - newFormula = `${shapeInformation.clipPathType}(${newFormulaValues.absoluteValueAxis} ${newFormulaValues.absoluteValueRadius} at ${shapeInformation.verticeCoordinates[0].x} ${shapeInformation.verticeCoordinates[0].y})`; - } - - setShapeInformation({ - ...shapeInformation, - "height": newFormulaValues.radius, - "formula": newFormula, - }); - - } else { - const newVerticeCoordinates = generateNewVerticeCoordinates(data.x, data.y, number, shapeInformation); - const newFormula = generateNewFormula(newVerticeCoordinates, shapeInformation); - - setShapeInformation({ - ...shapeInformation, - "verticeCoordinates": newVerticeCoordinates, - "formula": newFormula, - }); - } - - return; - } - - // If preview is clicked and the clipPathType is a polygon, add a verticeCoordinate value at its location and adjust formula - if ((event.target.id === "shapeShadow" || event.target.id === "clippedShape") && name === "click" && shapeInformation.clipPathType === "polygon") { - - const newVerticeCoordinates = generateNewVerticeCoordinates(event.nativeEvent.offsetX, event.nativeEvent.offsetY, shapeInformation.verticeCoordinates.length, shapeInformation); - const newFormula = generateNewFormula(newVerticeCoordinates, shapeInformation); - - setShapeInformation({ - ...shapeInformation, - "vertices": shapeInformation.vertices + 1, - "edges": shapeInformation.edges + 1, - "verticeCoordinates": newVerticeCoordinates, - "formula": newFormula, - }); - return; - } + if (value === "circle") { + setShapeInformation({ + ...shapeInformation, + ...circleInitialState, + }); + } - // If delete button is pressed and passes a number that corresponds to the vertice, remove the corresponding verticeCoordinate and adjust formula - if ((event.target.id.includes("deleteButton") - || event.target.parentElement.id.includes("deleteButton")) && number !== undefined) { + if (value === "ellipse") { + setShapeInformation({ + ...shapeInformation, + ...ellipseInitialState, + }); + } + + setShapeInformation((prevState) => ({ + ...prevState, + clipPathType: value, + edges: value === "polygon" ? 4 : 0, + vertices: value === "polygon" ? 4 : 0, + })); + return; + } - let newVerticeCoordinates = []; + if (name === "mousemove" || name === "touchmove") { + if (type === "width") { + const newFormulaValues = calculateRadiusAndFormulaFromMovement( + shapeInformation.verticeCoordinates[0].x, + shapeInformation.width, + shapeInformation.height, + data.x + ); + + let newFormula; + + if (shapeInformation.clipPathType === "circle") { + newFormula = `${shapeInformation.clipPathType}(${newFormulaValues.absoluteValueRadius} at ${shapeInformation.verticeCoordinates[0].x} ${shapeInformation.verticeCoordinates[0].y})`; + } else if (shapeInformation.clipPathType === "ellipse") { + newFormula = `${shapeInformation.clipPathType}(${newFormulaValues.absoluteValueRadius} ${newFormulaValues.absoluteValueAxis} at ${shapeInformation.verticeCoordinates[0].x} ${shapeInformation.verticeCoordinates[0].y})`; + } - for (let i = 0; i < shapeInformation.verticeCoordinates.length; i++) { - if (i !== number) { - newVerticeCoordinates.push(shapeInformation.verticeCoordinates[i]); - } - } + setShapeInformation({ + ...shapeInformation, + width: newFormulaValues.radius, + formula: newFormula, + }); + } else if (type === "height") { + const newFormulaValues = calculateRadiusAndFormulaFromMovement( + shapeInformation.verticeCoordinates[0].y, + shapeInformation.height, + shapeInformation.width, + data.y + ); + + let newFormula; + + if (shapeInformation.clipPathType === "ellipse") { + newFormula = `${shapeInformation.clipPathType}(${newFormulaValues.absoluteValueAxis} ${newFormulaValues.absoluteValueRadius} at ${shapeInformation.verticeCoordinates[0].x} ${shapeInformation.verticeCoordinates[0].y})`; + } - const newFormula = generateNewFormula(newVerticeCoordinates, shapeInformation); + setShapeInformation({ + ...shapeInformation, + height: newFormulaValues.radius, + formula: newFormula, + }); + } else { + const newVerticeCoordinates = generateNewVerticeCoordinates(data.x, data.y, number, shapeInformation); + const newFormula = generateNewFormula(newVerticeCoordinates, shapeInformation); - setShapeInformation({ - ...shapeInformation, - "vertices": shapeInformation.vertices - 1, - "edges": shapeInformation.edges - 1, - "verticeCoordinates": newVerticeCoordinates, - "formula": newFormula, - }); - return; - } - - // Handles all other ShapeForm and ShapePreview Changes setShapeInformation({ - ...shapeInformation, - [name]: value, + ...shapeInformation, + verticeCoordinates: newVerticeCoordinates, + formula: newFormula, }); + } + return; } - // Form Validation - const [validated, setValidated] = useState(false); + if ((event.target.id === "shapeShadow" || event.target.id === "clippedShape") && name === "click" && shapeInformation.clipPathType === "polygon") { + const newVerticeCoordinates = generateNewVerticeCoordinates(event.nativeEvent.offsetX, event.nativeEvent.offsetY, shapeInformation.verticeCoordinates.length, shapeInformation); + const newFormula = generateNewFormula(newVerticeCoordinates, shapeInformation); + + setShapeInformation({ + ...shapeInformation, + vertices: shapeInformation.vertices + 1, + edges: shapeInformation.edges + 1, + verticeCoordinates: newVerticeCoordinates, + formula: newFormula, + }); + return; + } - const handleSubmit = async(event) => { - event.preventDefault(); - const form = event.currentTarget; - if (form.checkValidity() === false) { - event.preventDefault(); - event.stopPropagation(); - } - setValidated(true); - - console.log(shapeInformation); - - // Editing Shape - if (props.edit) { - - const updateShapeResponse = await axios.post('/api/PUT/shape', { - shapeId: props.shape.shape_id, - name: shapeInformation.name, - formula: shapeInformation.formula, - vertices: shapeInformation.vertices, - visibility: shapeInformation.private, - edges: shapeInformation.edges, - notes: shapeInformation.notes, - type: shapeInformation.clipPathType, - backgroundColor: shapeInformation.backgroundColor - }); - const editShape = updateShapeResponse.data; - console.log({editShape}); - - if (editShape.data["update_hashes"].length > 0) { - props.handleClose(); - toast.success(`Shape ${shapeInformation.name} edited successfully.`); - props.setShapeAction({ - ...props.shapeAction, - "action": "edit", - "payload": { - "shape_id": editShape.data['update_hashes'] - } - }); - } else { - toast.error('OOPS!! We hit a bummer. Please try again.'); - } - - // Creating Shape - } else { - - // Create the shape in the DB - const insertShapeResponse = await axios.post('/api/POST/shape', { - name: shapeInformation.name, - formula: shapeInformation.formula, - vertices: shapeInformation.vertices, - visibility: shapeInformation.private, - edges: shapeInformation.edges, - notes: shapeInformation.notes, - type: shapeInformation.clipPathType, - backgroundColor: shapeInformation.backgroundColor, - createdBy: props.user.email, - likes: 0 - }); - const insertShape = insertShapeResponse.data - - console.log({insertShape}); - - // Create the user in the db - if (insertShape.data['inserted_hashes'].length > 0) { - // First check if the user exist - const userResponse = await axios.get("/api/GET/user", { - params: { - email: props.user.email - } - }); - const result = userResponse.data; - const count = result.length; - console.log({count}); - - // If doesn't exist, create in db - if (count === 0) { - const insertUserResponse = await axios.post('/api/POST/user', { - displayName: props.user.displayName, - email: props.user.email, - photoURL: props.user.photoURL - }); - const insertUser = insertUserResponse.data; - console.log({insertUser}); - } else { - console.log(`The user ${props.user.email} present in DB`); - } - - // Finally, close the modal and update the shape in UI - props.handleClose(); - if (props.setSearchTerm) { - props.setSearchTerm(''); - } - toast.success(`Shape ${shapeInformation.name} created successfully.`); - props.setShapeAction({ - ...props.shapeAction, - "action": "add", - "payload": { - "shape_id": insertShape.data['inserted_hashes'] - } - }); - - } else { - toast.error('OOPS!! We hit a bummer. Please try again.'); - } + if ((event.target.id.includes("deleteButton") || event.target.parentElement.id.includes("deleteButton")) && number !== undefined) { + let newVerticeCoordinates = []; + for (let i = 0; i < shapeInformation.verticeCoordinates.length; i++) { + if (i !== number) { + newVerticeCoordinates.push(shapeInformation.verticeCoordinates[i]); } + } + + const newFormula = generateNewFormula(newVerticeCoordinates, shapeInformation); + + setShapeInformation({ + ...shapeInformation, + vertices: shapeInformation.vertices - 1, + edges: shapeInformation.edges - 1, + verticeCoordinates: newVerticeCoordinates, + formula: newFormula, + }); + return; + } - setShapeInformation({ - ...initialState, - }); + setShapeInformation({ + ...shapeInformation, + [name]: value, + }); + }; - setValidated(false); - - } + const handleSubmit = async (event) => { + event.preventDefault(); + const form = event.currentTarget; - return( - <> - {setShapeInformation({ ...initialState }); props.handleClose(); }} - backdrop="static" - > - - {props.edit ? "Edit Shape" : "Create Shape"} - - - - - - - - - - - - - - - - - - - - - ); -} - -export default CreateShape; \ No newline at end of file + if (form.checkValidity() === false) { + event.preventDefault(); + event.stopPropagation(); + } + // The rest of the handleSubmit logic comes here + }; + + return ( + <> + { + setShapeInformation({ ...initialState }); + props.handleClose(); + }} + backdrop="static" + > + + {props.edit ? "Edit Shape" : "Create Shape"} + + + + + + + + + + + + + + + + + + + + ); +}; + +export default CreateShape;