diff --git a/client/src/components/Background/Background.jsx b/client/src/components/Background/Background.jsx index 175e4c17..f3dde5fd 100644 --- a/client/src/components/Background/Background.jsx +++ b/client/src/components/Background/Background.jsx @@ -4,6 +4,8 @@ import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; +import { ProjectBackgroundTypes } from '../../constants/Enums'; + import styles from './Background.module.scss'; import globalStyles from '../../styles.module.scss'; @@ -11,7 +13,8 @@ const Background = ({ type, name, imageUrl }) => (
{ - const data = { + onUpdate({ backgroundImage: null, - }; - - // TODO: move to services? - if (project.background && project.background.type === 'image') { - data.background = null; - } - - onUpdate(data); - }, [project.background, onUpdate]); + }); + }, [onUpdate]); if (step) { if (step) { diff --git a/client/src/components/Project/ActionsPopup/EditBackgroundStep.jsx b/client/src/components/Project/ActionsPopup/EditBackgroundStep.jsx index b3219e24..d50be73a 100644 --- a/client/src/components/Project/ActionsPopup/EditBackgroundStep.jsx +++ b/client/src/components/Project/ActionsPopup/EditBackgroundStep.jsx @@ -9,6 +9,7 @@ import { Button, Image } from 'semantic-ui-react'; import { FilePicker, Popup } from '../../../lib/custom-ui'; import ProjectBackgroundGradients from '../../../constants/ProjectBackgroundGradients'; +import { ProjectBackgroundTypes } from '../../../constants/Enums'; import styles from './EditBackgroundStep.module.scss'; import globalStyles from '../../../styles.module.scss'; @@ -30,15 +31,12 @@ const EditBackgroundStep = React.memo( const handleGradientClick = useCallback( (_, { value }) => { const background = { - type: 'gradient', + type: ProjectBackgroundTypes.GRADIENT, name: value, }; if (!dequal(background, defaultValue)) { - onUpdate({ - type: 'gradient', - name: value, - }); + onUpdate(background); } }, [defaultValue, onUpdate], @@ -46,7 +44,7 @@ const EditBackgroundStep = React.memo( const handleImageClick = useCallback(() => { const background = { - type: 'image', + type: ProjectBackgroundTypes.IMAGE, }; if (!dequal(background, defaultValue)) { @@ -93,7 +91,7 @@ const EditBackgroundStep = React.memo( className={classNames( styles.gradientButton, defaultValue && - defaultValue.type === 'gradient' && + defaultValue.type === ProjectBackgroundTypes.GRADIENT && gradient === defaultValue.name && styles.gradientButtonActive, globalStyles[`background${upperFirst(camelCase(gradient))}`], diff --git a/client/src/components/Project/ActionsPopup/EditBackgroundStep.module.scss b/client/src/components/Project/ActionsPopup/EditBackgroundStep.module.scss index 6b085b38..dcc3ff2d 100644 --- a/client/src/components/Project/ActionsPopup/EditBackgroundStep.module.scss +++ b/client/src/components/Project/ActionsPopup/EditBackgroundStep.module.scss @@ -66,6 +66,10 @@ .image { cursor: pointer; margin-bottom: 8px; + + &:hover { + opacity: 0.9; + } } .imageLabel { diff --git a/client/src/components/Projects/Projects.jsx b/client/src/components/Projects/Projects.jsx index a4bc8d8b..e11b711f 100755 --- a/client/src/components/Projects/Projects.jsx +++ b/client/src/components/Projects/Projects.jsx @@ -8,6 +8,7 @@ import { Link } from 'react-router-dom'; import { Container, Grid } from 'semantic-ui-react'; import Paths from '../../constants/Paths'; +import { ProjectBackgroundTypes } from '../../constants/Enums'; import { ReactComponent as PlusIcon } from '../../assets/images/plus-icon.svg'; import styles from './Projects.module.scss'; @@ -33,7 +34,7 @@ const Projects = React.memo(({ items, isEditable, onAdd }) => { styles.card, styles.open, item.background && - item.background.type === 'gradient' && + item.background.type === ProjectBackgroundTypes.GRADIENT && globalStyles[`background${upperFirst(camelCase(item.background.name))}`], )} style={{ diff --git a/client/src/constants/Enums.js b/client/src/constants/Enums.js index a7898eb8..400c252d 100755 --- a/client/src/constants/Enums.js +++ b/client/src/constants/Enums.js @@ -1,4 +1,8 @@ -// eslint-disable-next-line import/prefer-default-export +export const ProjectBackgroundTypes = { + GRADIENT: 'gradient', + IMAGE: 'image', +}; + export const ActionTypes = { CREATE_CARD: 'createCard', MOVE_CARD: 'moveCard', diff --git a/client/src/models/Project.js b/client/src/models/Project.js index 4e616d37..1558cc84 100755 --- a/client/src/models/Project.js +++ b/client/src/models/Project.js @@ -1,6 +1,7 @@ import { Model, attr, many } from 'redux-orm'; import ActionTypes from '../constants/ActionTypes'; +import { ProjectBackgroundTypes } from '../constants/Enums'; export default class extends Model { static modelName = 'Project'; @@ -28,10 +29,20 @@ export default class extends Model { }); break; - case ActionTypes.PROJECT_UPDATE: - Project.withId(payload.id).update(payload.data); + case ActionTypes.PROJECT_UPDATE: { + const project = Project.withId(payload.id); + project.update(payload.data); + + if ( + payload.data.backgroundImage === null && + project.background && + project.background.type === ProjectBackgroundTypes.IMAGE + ) { + project.background = null; + } break; + } case ActionTypes.PROJECT_DELETE: Project.withId(payload.id).deleteWithRelated(); diff --git a/server/api/controllers/projects/update.js b/server/api/controllers/projects/update.js index 0845d004..54f12f91 100755 --- a/server/api/controllers/projects/update.js +++ b/server/api/controllers/projects/update.js @@ -15,9 +15,35 @@ module.exports = { type: 'string', isNotEmptyString: true, }, - // TODO: add validation background: { type: 'json', + custom: (value) => { + if (_.isNull(value)) { + return true; + } + + if (!_.isPlainObject(value)) { + return false; + } + + if (!Project.BACKGROUND_TYPES.includes(value.type)) { + return false; + } + + if ( + value.type === 'gradient' && + _.size(value) === 2 && + Project.BACKGROUND_GRADIENTS.includes(value.name) + ) { + return true; + } + + if (value.type === 'image' && _.size(value) === 1) { + return true; + } + + return false; + }, }, backgroundImage: { type: 'json', diff --git a/server/api/helpers/update-project.js b/server/api/helpers/update-project.js index f94f1d6b..d98fb4c9 100644 --- a/server/api/helpers/update-project.js +++ b/server/api/helpers/update-project.js @@ -11,7 +11,7 @@ module.exports = { type: 'json', custom: (value) => _.isPlainObject(value) && - /* _.isUndefined(value.background) || _.isNull(value.background) && */ + (_.isUndefined(value.background) || _.isPlainObject(value.background)) && (_.isUndefined(value.backgroundImage) || _.isNull(value.backgroundImage)), required: true, }, @@ -20,6 +20,10 @@ module.exports = { }, }, + exits: { + invalidParams: {}, + }, + async fn(inputs, exits) { if (!_.isUndefined(inputs.values.backgroundImage)) { /* eslint-disable no-param-reassign */ @@ -33,9 +37,37 @@ module.exports = { inputs.values.background = { type: 'image', }; + } else if ( + _.isNull(inputs.values.backgroundImageDirname) && + inputs.record.background && + inputs.record.background.type === 'image' + ) { + inputs.values.background = null; // eslint-disable-line no-param-reassign } - const project = await Project.updateOne(inputs.record.id).set(inputs.values); + let project; + if (inputs.values.background && inputs.values.background.type === 'image') { + if (_.isNull(inputs.values.backgroundImageDirname)) { + throw 'invalidParams'; + } + + if (_.isUndefined(inputs.values.backgroundImageDirname)) { + project = await Project.updateOne({ + id: inputs.record.id, + backgroundImageDirname: { + '!=': null, + }, + }).set(inputs.values); + + if (!project) { + delete inputs.values.background; // eslint-disable-line no-param-reassign + } + } + } + + if (!project) { + project = await Project.updateOne(inputs.record.id).set(inputs.values); + } if (project) { if ( diff --git a/server/api/models/Project.js b/server/api/models/Project.js index ea895779..ff12e0a1 100755 --- a/server/api/models/Project.js +++ b/server/api/models/Project.js @@ -5,7 +5,40 @@ * @docs :: https://sailsjs.com/docs/concepts/models-and-orm/models */ +const BACKGROUND_TYPES = ['gradient', 'image']; + +const BACKGROUND_GRADIENTS = [ + 'old-lime', + 'ocean-dive', + 'tzepesch-style', + 'jungle-mesh', + 'strawberry-dust', + 'purple-rose', + 'sun-scream', + 'warm-rust', + 'sky-change', + 'green-eyes', + 'blue-xchange', + 'blood-orange', + 'sour-peel', + 'green-ninja', + 'algae-green', + 'coral-reef', + 'steel-grey', + 'heat-waves', + 'velvet-lounge', + 'purple-rain', + 'blue-steel', + 'blueish-curve', + 'prism-light', + 'green-mist', + 'red-curtain', +]; + module.exports = { + BACKGROUND_TYPES, + BACKGROUND_GRADIENTS, + attributes: { // ╔═╗╦═╗╦╔╦╗╦╔╦╗╦╦ ╦╔═╗╔═╗ // ╠═╝╠╦╝║║║║║ ║ ║╚╗╔╝║╣ ╚═╗