diff --git a/api-server/src/server/boot/settings.js b/api-server/src/server/boot/settings.js index fe4a45e3530..d1a4b4006cf 100644 --- a/api-server/src/server/boot/settings.js +++ b/api-server/src/server/boot/settings.js @@ -115,23 +115,14 @@ function updateMyEmail(req, res, next) { // } function updateMyPortfolio(...args) { - const portfolioKeys = [ - 'id', - 'title', - 'description', - 'url', - 'image', - 'isSaved' - ]; + const portfolioKeys = ['id', 'title', 'description', 'url', 'image']; const buildUpdate = body => { const portfolio = body?.portfolio?.map(elem => _.pick(elem, portfolioKeys)); return { portfolio }; }; const validate = ({ portfolio }) => portfolio?.every(isPortfolioElement); const isPortfolioElement = elem => - Object.values(elem).every( - val => typeof val == 'string' || typeof val === 'boolean' - ); + Object.values(elem).every(val => typeof val == 'string'); createUpdateUserProperties(buildUpdate, validate)(...args); } diff --git a/client/src/components/settings/PreventableButton.jsx b/client/src/components/settings/PreventableButton.jsx deleted file mode 100644 index a89d6724cfc..00000000000 --- a/client/src/components/settings/PreventableButton.jsx +++ /dev/null @@ -1,25 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import { Button } from '@freecodecamp/react-bootstrap'; - -const PreventableButton = ({ handleAdd, t, portfolio }) => { - const [isDisabled, setIsDisabled] = useState(false); - useEffect(() => { - const found = portfolio.find(item => !item.isSaved); - return found ? setIsDisabled(true) : setIsDisabled(false); - }, [portfolio.length, portfolio]); - - return ( - - ); -}; - -export default PreventableButton; diff --git a/client/src/components/settings/portfolio.tsx b/client/src/components/settings/portfolio.tsx index f691550e47a..370277f1975 100644 --- a/client/src/components/settings/portfolio.tsx +++ b/client/src/components/settings/portfolio.tsx @@ -5,9 +5,9 @@ import { FormControl, HelpBlock } from '@freecodecamp/react-bootstrap'; -import { findIndex, find, isEqual, omit } from 'lodash-es'; +import { findIndex, find, isEqual } from 'lodash-es'; import { nanoid } from 'nanoid'; -import React, { Component, FormEvent } from 'react'; +import React, { Component } from 'react'; import { TFunction, withTranslation } from 'react-i18next'; import isURL from 'validator/lib/isURL'; @@ -16,10 +16,8 @@ import { hasProtocolRE } from '../../utils'; import { FullWidthRow, ButtonSpacer, Spacer } from '../helpers'; import BlockSaveButton from '../helpers/form/block-save-button'; import SectionHeader from './section-header'; -import PreventableButton from './PreventableButton'; -type PortfolioValues = { - isSaved: boolean; +type PortfolioItem = { id: string; description: string; image: string; @@ -28,38 +26,32 @@ type PortfolioValues = { }; type PortfolioProps = { - isSaved: boolean; picture?: string; - portfolio: PortfolioValues[]; + portfolio: PortfolioItem[]; t: TFunction; - updatePortfolio: (obj: { portfolio: PortfolioValues[] }) => void; + updatePortfolio: (obj: { portfolio: PortfolioItem[] }) => void; username?: string; }; type PortfolioState = { - portfolio: PortfolioValues[]; + portfolio: PortfolioItem[]; + unsavedItemId: string | null; }; -function createEmptyPortfolio() { +function createEmptyPortfolioItem(): PortfolioItem { return { id: nanoid(), title: '', description: '', url: '', - image: '', - isSaved: false + image: '' }; } function createFindById(id: string) { - return (p: PortfolioValues) => p.id === id; + return (p: PortfolioItem) => p.id === id; } -const mockEvent = { - // eslint-disable-next-line @typescript-eslint/no-empty-function - preventDefault() {} -}; - class PortfolioSettings extends Component { static displayName: string; constructor(props: PortfolioProps) { @@ -68,7 +60,8 @@ class PortfolioSettings extends Component { const { portfolio = [] } = props; this.state = { - portfolio: [...portfolio] + portfolio: [...portfolio], + unsavedItemId: null }; } @@ -91,35 +84,33 @@ class PortfolioSettings extends Component { }); }; - handleSubmit = (e: React.FormEvent) => { + handleSubmit = (e: React.FormEvent, id: string) => { e.preventDefault(); - const target = e.target as HTMLInputElement; - const id = target?.id || undefined; - const { updatePortfolio } = this.props; - let { portfolio } = this.state; - if (id) { - portfolio = portfolio.map(item => - item.id === id ? { ...item, isSaved: true } : item - ); - this.setState({ - portfolio - }); + this.updateItem(id); + }; + + updateItem = (id: string) => { + const { portfolio, unsavedItemId } = this.state; + if (unsavedItemId === id) { + this.setState({ unsavedItemId: null }); } - return updatePortfolio({ portfolio }); + this.props.updatePortfolio({ portfolio }); }; handleAdd = () => { - return this.setState(state => ({ - portfolio: [createEmptyPortfolio(), ...state.portfolio] + const item = createEmptyPortfolioItem(); + this.setState(state => ({ + portfolio: [item, ...state.portfolio], + unsavedItemId: item.id })); }; handleRemoveItem = (id: string) => { - return this.setState( + this.setState( state => ({ portfolio: state.portfolio.filter(p => p.id !== id) }), - () => this.handleSubmit(mockEvent as FormEvent) + () => this.updateItem(id) ); }; @@ -131,7 +122,7 @@ class PortfolioSettings extends Component { return false; } const edited = find(portfolio, createFindById(id)); - return isEqual(omit(original, ['isSaved']), omit(edited, ['isSaved'])); + return isEqual(original, edited); }; // TODO: Check if this function is required or not @@ -211,9 +202,9 @@ class PortfolioSettings extends Component { } renderPortfolio = ( - portfolio: PortfolioValues, + portfolio: PortfolioItem, index: number, - arr: PortfolioValues[] + arr: PortfolioItem[] ) => { const { t } = this.props; const { id, title, description, url, image } = portfolio; @@ -230,7 +221,7 @@ class PortfolioSettings extends Component { return (
-
+ this.handleSubmit(e, id)}> { render() { const { t } = this.props; - const { portfolio = [] } = this.state; + const { portfolio = [], unsavedItemId } = this.state; return (
{t('settings.headings.portfolio')} @@ -338,11 +329,16 @@ class PortfolioSettings extends Component { - + {portfolio.length ? portfolio.map(this.renderPortfolio) : null}