Skip to content

Commit 762cf7a

Browse files
authored
Merge pull request #38 from TryShape/issue-11-add-functionality-to-create-new-shapes
Issue 11 add functionality to create new shapes
2 parents 66c5054 + 3ac9e43 commit 762cf7a

4 files changed

Lines changed: 203 additions & 136 deletions

File tree

components/core/CreateShape.js

Lines changed: 145 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,26 @@
11
import React, { useState } from "react";
2+
3+
// Bootstrap
24
import Container from "react-bootstrap/Container";
35
import Row from "react-bootstrap/Row";
46
import Col from "react-bootstrap/Col";
57
import Modal from "react-bootstrap/Modal";
68
import Button from "react-bootstrap/Button";
79

10+
// ShapeForm and ShapePreview Components
11+
import { ShapeForm, ShapePreview } from "..";
12+
813
// Toast
914
import toast from "react-hot-toast";
1015

1116
// harperDb fetch call
1217
import { harperFetch } from "../../utils/HarperFetch";
1318

14-
import { ShapeForm, ShapePreview } from "..";
15-
1619
const 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

Comments
 (0)