11import React , { useState } from "react" ;
2+
3+ // Bootstrap
24import Container from "react-bootstrap/Container" ;
35import Row from "react-bootstrap/Row" ;
46import Col from "react-bootstrap/Col" ;
57import Modal from "react-bootstrap/Modal" ;
68import Button from "react-bootstrap/Button" ;
79
10+ // ShapeForm and ShapePreview Components
11+ import { ShapeForm , ShapePreview } from ".." ;
12+
813// Toast
914import toast from "react-hot-toast" ;
1015
1116// harperDb fetch call
1217import { harperFetch } from "../../utils/HarperFetch" ;
1318
14- import { ShapeForm , ShapePreview } from ".." ;
15-
1619const CreateShape = ( props ) => {
17- const [ shapeInformation , setShapeInformation ] = useState ( {
18- "name" : "Tilted Square" ,
20+
21+ // Store the default state as a variable so resetting form is easier
22+ const initialState = {
23+ "name" : "" ,
1924 "formula" : "polygon(10% 10%, 90% 10%, 90% 90%, 10% 80%)" ,
2025 "vertices" : 4 ,
2126 "private" : false ,
@@ -42,30 +47,38 @@ const CreateShape = (props) => {
4247 "y" : "80%" ,
4348 } ,
4449 ]
50+ }
51+
52+ // shapeInformation holds all information about the shape
53+ const [ shapeInformation , setShapeInformation ] = useState ( {
54+ ...initialState ,
4555 } ) ;
4656
47- function handleChange ( event , data , number ) {
57+ // Changes shapeInformation when something in ShapeForm or ShapePreview is altered
58+ const handleChange = ( event , data , number ) => {
59+
60+ // console.log(event, data);
61+
4862 const name = event . target . name || event . type ;
4963 const value = event . target . type === "checkbox" ? event . target . checked : event . target . value ;
5064
51- // console.log(event, data);
52-
65+ // If Clip-Path formula value is changed, it makes sure that the parentheses stay there and also alters the verticeCoordinates value
5366 if ( name === "name" ) {
5467 setShapeInformation ( {
5568 ...shapeInformation ,
5669 "name" : value ,
5770 } ) ;
58- } else if ( name === 'private' ) {
59- setShapeInformation ( {
60- ...shapeInformation ,
61- "private" : ! shapeInformation . private ,
62-
63- } ) ;
64- } else if ( name === "formula" ) {
65- const edgeVerticeNumber = shapeInformation . clipPathType === "polygon" ? value . split ( "," ) . length : 0 ;
71+ return ;
72+ }
73+
74+ // If formula value is changed, alter formula value and verticeCoordinates value depending on clipPathType
75+ if ( name === "formula" ) {
6676
77+ const edgeVerticeNumber = shapeInformation . clipPathType === "polygon" && value !== "" ? value . split ( "," ) . length : 0 ;
78+
79+ // If user deletes all, set formula to the Clip-Path type with an empty set of parentheses
6780 if ( value === "" ) {
68- handleFormulaChange ( shapeInformation . clipPathType + "()" , edgeVerticeNumber )
81+ handleFormulaChange ( shapeInformation . clipPathType + "()" , edgeVerticeNumber ) ;
6982 } else if ( value . includes ( "polygon" ) ) {
7083 handleFormulaChange ( value , edgeVerticeNumber , "polygon" ) ;
7184 } else if ( value . includes ( "circle" ) ) {
@@ -75,7 +88,50 @@ const CreateShape = (props) => {
7588 } else {
7689 handleFormulaChange ( value , edgeVerticeNumber ) ;
7790 }
78- } else if ( name === "mousemove" ) {
91+ return ;
92+
93+ }
94+
95+ // If Clip-Path Type is changed, change the value of the clipPathType
96+ if ( name === "clipPathType" ) {
97+
98+ if ( value === "polygon" ) {
99+ setShapeInformation ( {
100+ ...initialState ,
101+ } ) ;
102+ }
103+
104+ if ( value === "circle" ) {
105+ setShapeInformation ( {
106+ ...shapeInformation ,
107+ "type" : "circle" ,
108+ "formula" : "circle(50% at 50% 50%)" ,
109+ } ) ;
110+ }
111+
112+ if ( value === "ellipse" ) {
113+ setShapeInformation ( {
114+ ...shapeInformation ,
115+ "type" : "ellipse" ,
116+ "formula" : "ellipse(25% 40% at 50% 50%)" ,
117+ } ) ;
118+ }
119+
120+ setShapeInformation ( prevState => {
121+ return {
122+ ...prevState ,
123+ "clipPathType" : value ,
124+ "edges" : value === "polygon" ? 4 : 0 ,
125+ "vertices" : value === "polygon" ? 4 : 0 ,
126+ "notes" : "" ,
127+ }
128+ } ) ;
129+ return ;
130+ }
131+
132+ // If DraggableVertice is moved, adjust verticeCoordinates and formula
133+ if ( name === "mousemove" ) {
134+
79135 const newVerticeCoordinates = addNewVerticeCoordinates ( data . x , data . y , number ) ;
80136 const newFormula = generateNewFormula ( newVerticeCoordinates ) ;
81137
@@ -84,7 +140,12 @@ const CreateShape = (props) => {
84140 "verticeCoordinates" : newVerticeCoordinates ,
85141 "formula" : newFormula ,
86142 } ) ;
87- } else if ( name === "click" && event . target . id === "shapeShadow" ) {
143+ return ;
144+ }
145+
146+ // If preview is clicked and the clipPathType is a polygon, add a verticeCoordinate value at its location and adjust formula
147+ if ( ( event . target . id === "shapeShadow" || event . target . id === "clippedShape" ) && name === "click" && shapeInformation . clipPathType === "polygon" ) {
148+
88149 const newVerticeCoordinates = addNewVerticeCoordinates ( event . nativeEvent . offsetX , event . nativeEvent . offsetY , shapeInformation . verticeCoordinates . length ) ;
89150 const newFormula = generateNewFormula ( newVerticeCoordinates ) ;
90151
@@ -95,7 +156,11 @@ const CreateShape = (props) => {
95156 "verticeCoordinates" : newVerticeCoordinates ,
96157 "formula" : newFormula ,
97158 } ) ;
98- } else if ( ( event . target . id . includes ( "deleteButton" ) || event . target . localName === "line" ) && number !== undefined ) {
159+ return ;
160+ }
161+
162+ // If delete button is pressed and passes a number that corresponds to the vertice, remove the corresponding verticeCoordinate and adjust formula
163+ if ( event . target . id . includes ( "deleteButton" ) && number !== undefined ) {
99164
100165 let newVerticeCoordinates = [ ] ;
101166
@@ -114,44 +179,20 @@ const CreateShape = (props) => {
114179 "verticeCoordinates" : newVerticeCoordinates ,
115180 "formula" : newFormula ,
116181 } ) ;
117-
118- } else if ( name === "clipPathType" ) {
119- handleClipPathChange ( value ) ;
120- } else {
121- setShapeInformation ( {
122- ...shapeInformation ,
123- [ name ] : value ,
124- } ) ;
182+ return ;
125183 }
126- }
127-
128- function addNewVerticeCoordinates ( x , y , number ) {
129- const xPercentage = Math . round ( ( x / 280.0 ) * 100.0 ) ;
130- const yPercentage = Math . round ( ( y / 280.0 ) * 100.0 ) ;
131-
132- let newVerticeCoordinates = shapeInformation . verticeCoordinates ;
133- newVerticeCoordinates [ number ] = {
134- "x" : xPercentage + "%" ,
135- "y" : yPercentage + "%"
136- }
137-
138- return newVerticeCoordinates ;
139- }
140-
141- function generateNewFormula ( newVerticeCoordinates ) {
142- let newFormula = shapeInformation . clipPathType + "(" ;
143-
144- for ( let i = 0 ; i < newVerticeCoordinates . length ; i ++ ) {
145- let newX = newVerticeCoordinates [ i ] . x ;
146- let newY = newVerticeCoordinates [ i ] . y ;
147-
148- i === newVerticeCoordinates . length - 1 ? newFormula = newFormula + newX + " " + newY + ")" : newFormula = newFormula + newX + " " + newY + ", " ;
149- }
150-
151- return newFormula ;
184+
185+ // Handles all other ShapeForm and ShapePreview Changes
186+ setShapeInformation ( {
187+ ...shapeInformation ,
188+ [ name ] : value ,
189+ } ) ;
152190 }
153191
154- function handleFormulaChange ( formula , edgeVerticeNumber , clipPathType ) {
192+ // Called when there is a change in the textbox for formula in the form
193+ // Adjusts verticeCoordinates, vertices, and edges accordingly
194+ // Ensures that the parentheses remain
195+ const handleFormulaChange = ( formula , edgeVerticeNumber , clipPathType ) => {
155196 let newVerticeCoordinates = [ ] ;
156197
157198 if ( clipPathType === "polygon" ) {
@@ -176,44 +217,42 @@ const CreateShape = (props) => {
176217 "verticeCoordinates" : newVerticeCoordinates ,
177218 }
178219 } ) ;
179- }
220+ }
180221
181- function handleClipPathChange ( clipPathType ) {
182- if ( clipPathType === "polygon" ) {
183- setShapeInformation ( {
184- ...shapeInformation ,
185- "name" : "Tilted Square" ,
186- "formula" : "polygon(10% 10%, 90% 10%, 90% 90%, 10% 80%)" ,
187- } ) ;
222+ // Returns an array that has a new verticeCoordinate
223+ const addNewVerticeCoordinates = ( x , y , number ) => {
224+ const xPercentage = Math . round ( ( x / 280.0 ) * 100.0 ) ;
225+ const yPercentage = Math . round ( ( y / 280.0 ) * 100.0 ) ;
226+
227+ let newVerticeCoordinates = shapeInformation . verticeCoordinates ;
228+ newVerticeCoordinates [ number ] = {
229+ "x" : xPercentage + "%" ,
230+ "y" : yPercentage + "%"
188231 }
189232
190- if ( clipPathType === "circle" ) {
191- setShapeInformation ( {
192- ...shapeInformation ,
193- "name" : "Circle" ,
194- "formula" : "circle(50% at 50% 50%)" ,
195- } ) ;
233+ return newVerticeCoordinates ;
234+ }
235+
236+ // Returns a generated formula string from a verticeCoordinate array
237+ const generateNewFormula = ( newVerticeCoordinates ) => {
238+
239+ let newFormula = shapeInformation . clipPathType + "(" ;
240+
241+ if ( newVerticeCoordinates . length === 0 ) {
242+ return newFormula + ")" ;
196243 }
197244
198- if ( clipPathType === "ellipse" ) {
199- setShapeInformation ( {
200- ...shapeInformation ,
201- "name" : "Ellipse" ,
202- "formula" : "ellipse(25% 40% at 50% 50%)" ,
203- } ) ;
245+ for ( let i = 0 ; i < newVerticeCoordinates . length ; i ++ ) {
246+ let newX = newVerticeCoordinates [ i ] . x ;
247+ let newY = newVerticeCoordinates [ i ] . y ;
248+
249+ i === newVerticeCoordinates . length - 1 ? newFormula = newFormula + newX + " " + newY + ")" : newFormula = newFormula + newX + " " + newY + ", " ;
204250 }
205251
206- setShapeInformation ( prevState => {
207- return {
208- ...prevState ,
209- "clipPathType" : clipPathType ,
210- "edges" : clipPathType === "polygon" ? 4 : 0 ,
211- "vertices" : clipPathType === "polygon" ? 4 : 0 ,
212- "notes" : "" ,
213- }
214- } )
252+ return newFormula ;
215253 }
216254
255+ // Form Validation
217256 const [ validated , setValidated ] = useState ( false ) ;
218257
219258 const handleSubmit = async ( event ) => {
@@ -255,29 +294,28 @@ const CreateShape = (props) => {
255294 } else {
256295 console . log ( `The user ${ props . user . email } present in DB` ) ;
257296 }
297+
298+ // Finally, close the modal and update the shape in UI
299+ props . handleClose ( ) ;
300+ toast . success ( `Shape ${ shapeInformation . name } created successfully.` ) ;
301+ props . setShapeAction ( {
302+ ...props . shapeAction ,
303+ "action" : "add" ,
304+ "payload" : {
305+ "shape_id" : insertShape [ 'inserted_hashes' ]
306+ }
307+ } ) ;
308+
309+ setShapeInformation ( {
310+ ...initialState ,
311+ } ) ;
312+
313+ setValidated ( false ) ;
314+
315+ } else {
316+ toast . error ( 'OOPS!! We hit a bummer. Please try again.' ) ;
258317 }
259- props . handleClose ( ) ;
260- toast . success ( `Shape ${ shapeInformation . name } created successfully.` ) ;
261- props . setShapeAction ( {
262- ...props . shapeAction ,
263- "action" : "add" ,
264- "payload" : {
265- "backgroundColor" : shapeInformation . backgroundColor ,
266- "createdAt" : null ,
267- "createdBy" : props . user . email ,
268- "edges" : shapeInformation . edges ,
269- "email" : null ,
270- "email1" : props . user . email ,
271- "formula" : shapeInformation . formula ,
272- "likes" : 0 ,
273- "name" : shapeInformation . name ,
274- "name1" : props . user . displayName ,
275- "notes" : shapeInformation . notes ,
276- "photoURL" : props . user . photoURL ,
277- "private" : shapeInformation . private ,
278- "type" : shapeInformation . clipPathType
279- }
280- } ) ;
318+
281319 }
282320
283321 return (
@@ -286,7 +324,7 @@ const CreateShape = (props) => {
286324 show = { props . show }
287325 centered
288326 size = "lg"
289- onHide = { props . handleClose }
327+ onHide = { ( ) => { setShapeInformation ( { ... initialState } ) ; props . handleClose ( ) ; } }
290328 backdrop = "static"
291329 >
292330 < Modal . Header closeButton >
@@ -313,7 +351,7 @@ const CreateShape = (props) => {
313351 </ Container >
314352 </ Modal . Body >
315353 < Modal . Footer >
316- < Button onClick = { ( ) => props . handleClose ( ) } variant = "outline-info" >
354+ < Button onClick = { ( ) => { setShapeInformation ( { ... initialState } ) ; props . handleClose ( ) ; } } variant = "outline-info" >
317355 Close
318356 </ Button >
319357 < Button variant = "secondary" type = "submit" form = "createShapeForm" disabled = { ! shapeInformation . name } >
0 commit comments