Skip to content

Commit

Permalink
Enhancement/update categories=page (#237)
Browse files Browse the repository at this point in the history
* Delete unused components

* 🚚 Move files to new directory

* ✨Create new components for PhotoPage form

* ♻️Refactor PhotoPage

* Prepare for release

* Add instruction line

* ✨Use dropdown label on brand

* 🐛Improve delete category handling

* ✨Add click to enlarge photo

* 🐛 Fix issues from rebasing

* 🐛fix import path
  • Loading branch information
munroTom authored and Sebastian Ovide committed Oct 3, 2019
1 parent 20c8902 commit 6bb2b1a
Show file tree
Hide file tree
Showing 35 changed files with 1,008 additions and 1,016 deletions.
4 changes: 3 additions & 1 deletion jsconfig.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
{
"compilerOptions": { "baseUrl": "src" }
"compilerOptions": {
"baseUrl": "src"
}
}
4 changes: 4 additions & 0 deletions src/App.scss
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,7 @@ body {
.firebaseui-link.firebaseui-id-secondary-link {
//color: $secondary !important;
}

.body {
font-family: "Roboto", "Helvetica", "Arial", sans-serif;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { withStyles } from "@material-ui/core/styles";

import _ from "lodash";

import "./style.scss";
import "../style.scss";

const styles = theme => ({
pictureThumbnail: {
Expand Down
212 changes: 212 additions & 0 deletions src/components/PhotoPage/AdminApproval/MultiFields.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
import React from "react";
import SelectControlSingleValue from "./SelectControlSingleValue";
import RemoveIcon from "@material-ui/icons/RemoveCircleOutline";
import Button from "@material-ui/core/Button";
import { withStyles } from "@material-ui/core/styles";
import { getValueAndAncestorsFromTree } from "../../../utils";

const styles = theme => ({});

class MultiFields extends React.Component {
state = {
fieldValues: []
};

textFieldValueError = this.props.field.subfields
? Object.values(this.props.field.subfields).reduce((a, v) => {
a[v.name] = { value: "", error: !"".match(v.regexValidation) };
return a;
}, {})
: false;

selectValue = {
leafkey: {
value: ""
}
};

handleClickAdd = e => {
const fieldValues = [...this.state.fieldValues];
fieldValues.push({
...JSON.parse(JSON.stringify(this.textFieldValueError)),
...JSON.parse(JSON.stringify(this.selectValue))
});

this.setState({
fieldValues
});
};

handleClickRemove = index => e => {
const length = this.state.fieldValues.length;
if (index === 0 && length === 1) {
this.setState({
fieldValues: [
{
...JSON.parse(JSON.stringify(this.textFieldValueError)),
...JSON.parse(JSON.stringify(this.selectValue))
}
]
});
this.props.handleChange(null, false);
} else {
const fieldValues = this.state.fieldValues.filter(
(fieldValue, loop_index) => loop_index !== index
);
this.setState({
fieldValues
});
this.checkErrorAndPropagateResToParent(fieldValues);
}
};

checkErrorAndPropagateResToParent = values => {
let res = [];
let textFieldErrors = false;
Object.values(values).forEach((obj, index) => {
res.push({});
Object.entries(obj).forEach(([key, value]) => {
res[index][key] = value.value;
if (value.error && values[index].leafkey.value) {
textFieldErrors = true;
}
});
});
this.props.handleChange(res, textFieldErrors);
};

handleChangeSelect = index => (value, error) => {
const fieldValues = [...this.state.fieldValues];
fieldValues[index].leafkey.value = value;

this.setState({
fieldValues
});
this.checkErrorAndPropagateResToParent(fieldValues);
};

handleChangeTitleTextField = (index, field) => (value, error) => {
const fieldValues = [...this.state.fieldValues];
fieldValues[index][field.name].error = error;
fieldValues[index][field.name].value = value;

this.setState({
fieldValues
});
this.checkErrorAndPropagateResToParent(fieldValues);
};

static toFormattedString = (s, data) => {
const categories = typeof s === "string" ? JSON.parse(s) : s;
let categoryId;
return (
categories &&
categories.map((category, index) => (
<div key={index}>
{index === 0 && <br />}
<div>Category {index}</div>
{Object.entries(category).map(([key, value]) => {
let formattedValue = value;
let formattedKey = key;
if (key === "leafkey") {
formattedValue = getValueAndAncestorsFromTree(
data,
value
).toString();
categoryId = value;
formattedKey = "category";
}
return (
<div style={{ display: "flex" }} key={key}>
<div style={{ fontWeight: 100 }}>{formattedKey}</div> :{" "}
<div>{formattedValue}</div>
</div>
);
})}
<div style={{ display: "flex" }}>
<div style={{ fontWeight: 100 }}>categoryId</div> :{" "}
<div>{categoryId}</div>
</div>
<br />
</div>
))
);
};

componentDidMount() {
this.handleClickAdd();
}

render() {
return (
<div>
{this.state.fieldValues.map((fieldValue, index) => {
return (
<div key={index}>
<br />
<br />
<div style={{ display: "flex" }}>
<SelectControlSingleValue
single={fieldValue.leafkey.value}
handleChangeSelect={this.handleChangeSelect(index)}
{...this.props}
/>
<div
style={{
marginBottom: this.props.theme.spacing(0.5),
display: "flex",
alignItems: "flex-end"
}}
>
<RemoveIcon onClick={this.handleClickRemove(index)} />
</div>
</div>
{this.props.field.subfields &&
fieldValue &&
fieldValue.leafkey.value && (
<div>
{Object.values(this.props.field.subfields).map(
(subfield, index_subfield) => {
return (
<div
key={"subcomponent_" + index_subfield}
style={{ marginTop: this.props.theme.spacing(1) }}
>
<subfield.component
field={subfield}
handleChange={this.handleChangeTitleTextField(
index,
subfield
)}
fieldValue={fieldValue[subfield.name]}
/>
</div>
);
}
)}
{index === this.state.fieldValues.length - 1 && (
<div style={{ marginTop: this.props.theme.spacing(1.5) }}>
<Button
disabled={this.props.error}
fullWidth
variant="outlined"
onClick={this.handleClickAdd}
>
add another category
</Button>
</div>
)}
</div>
)}
</div>
);
})}
</div>
);
}
}

export default {
MultiFieldsWithStyles: withStyles(styles, { withTheme: true })(MultiFields),
MultiFieldsOriginal: MultiFields
};
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import MenuItem from '@material-ui/core/MenuItem';
import CancelIcon from '@material-ui/icons/Cancel';
import { emphasize } from '@material-ui/core/styles/colorManipulator';
import _ from 'lodash';
import { getValueFromTree } from '../../utils';
import { getValueFromTree } from '../../../utils';


const styles = theme => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React, { Component } from 'react';
import { withStyles } from '@material-ui/core/styles';
import TextField from '@material-ui/core/TextField';

import enums from '../../types/enums';
import enums from '../../../types/enums';

const styles = theme => ({
cssUnderline: {
Expand Down
74 changes: 74 additions & 0 deletions src/components/PhotoPage/CategoryField/components/Category.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React, { useState, useEffect, useCallback } from "react";

import RemoveIcon from "@material-ui/icons/RemoveCircleOutline";

import { FieldLabelWithInput } from "./CategoryDropdown/FieldLabel";

import { validateString, validateIsPositiveNumber } from "./validation";
import CategoryDropdown from "./CategoryDropdown";

import "./Category.scss";

const CategoryField = ({ handleClickRemove, handleChange }) => {
const [numberOfPieces, setNumberOfPieces] = useState("");
const [brand, setBrand] = useState("");
const [selectedOption, setSelectedOption] = useState("");

const handleChangeCallback = useCallback(value => handleChange(value), [
handleChange
]);

//TODO: come up with a nicer way of doing this with the whole tree
useEffect(() => {
const validBrand = validateString(brand);
const validCategory =
validBrand &&
validateIsPositiveNumber(numberOfPieces) &&
validateIsPositiveNumber(selectedOption && selectedOption.key);

handleChangeCallback({
leafKey: selectedOption && selectedOption.key,
number: numberOfPieces,
brand: validBrand && brand.trim(),
error: !validCategory
});
}, [numberOfPieces, brand, selectedOption]);

return (
<div className={"CategoryField__container"}>
<div className="CategoryField__dropdownContainer">
<CategoryDropdown
label="Type of rubbish"
placeholder={"e.g. plastic bottle"}
value={selectedOption}
setValue={setSelectedOption}
/>
<RemoveIcon onClick={handleClickRemove} />
</div>

{selectedOption && (
<>
<FieldLabelWithInput
label={`Brand of ${selectedOption.label}`}
placeholder={'e.g. coca cola or "none"'}
value={brand}
setValue={setBrand}
validationFn={validateString}
required
/>

<FieldLabelWithInput
label="Number of pieces"
placeholder={"e.g. 1"}
validationFn={validateIsPositiveNumber}
value={numberOfPieces}
setValue={setNumberOfPieces}
required
/>
</>
)}
</div>
);
};

export default CategoryField;
12 changes: 12 additions & 0 deletions src/components/PhotoPage/CategoryField/components/Category.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.CategoryField__container {
margin-top: 10px;
background: rgba(0, 0, 0, 0.09);
border-radius: 8px;
padding: 5px;
}

.CategoryField__dropdownContainer {
display: flex;
flex-direction: row;
align-items: center;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from "react";

import "./FieldLabel.scss";

const FieldLabel = ({ label, required, children }) => {
return (
<div className={"FieldLabel__container"}>
<p className={"FieldLabel__label"}>
{label}
{required && <span className={"FieldLabel__required"}> *</span>}
</p>
{children}
</div>
);
};

export default FieldLabel;
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
@import "custom/config.scss";

.FieldLabel__container {
margin: 10px 0;
width: 100%;
}

.FieldLabel__label {
margin: 0;
font-size: 13px;
margin-bottom: 5px;
}

.FieldLabel__required {
color: red;
}
Loading

0 comments on commit 6bb2b1a

Please sign in to comment.