import { FormGroup, ControlLabel, FormControl, HelpBlock, Alert } from '@freecodecamp/react-bootstrap'; import React, { Component } from 'react'; import type { TFunction } from 'i18next'; import { withTranslation } from 'react-i18next'; import isURL from 'validator/lib/isURL'; import { FullWidthRow, Spacer } from '../helpers'; import BlockSaveButton from '../helpers/form/block-save-button'; import type { CamperProps } from '../profile/components/camper'; import SoundSettings from './sound'; import ThemeSettings, { type ThemeProps } from './theme'; import UsernameSettings from './username'; import KeyboardShortcutsSettings from './keyboard-shortcuts'; import SectionHeader from './section-header'; import ScrollbarWidthSettings from './scrollbar-width'; type AboutProps = ThemeProps & Omit< CamperProps, | 'linkedin' | 'joinDate' | 'isDonating' | 'githubProfile' | 'twitter' | 'website' | 'yearsTopContributor' > & { sound: boolean; keyboardShortcuts: boolean; submitNewAbout: (formValues: FormValues) => void; t: TFunction; toggleSoundMode: (sound: boolean) => void; toggleKeyboardShortcuts: (keyboardShortcuts: boolean) => void; }; type FormValues = Pick; type AboutState = { formValues: FormValues; originalValues: FormValues; formClicked: boolean; isPictureUrlValid: boolean; }; const ShowImageValidationWarning = ({ alertContent }: { alertContent: string; }) => { return ( {alertContent} ); }; class AboutSettings extends Component { validationImage: HTMLImageElement; static displayName: string; constructor(props: AboutProps) { super(props); this.validationImage = new Image(); const { name = '', location = '', picture = '', about = '' } = props; const values = { name, location, picture, about }; this.state = { formValues: { ...values }, originalValues: { ...values }, formClicked: false, isPictureUrlValid: true }; } componentDidUpdate() { const { name, location, picture, about } = this.props; const { formValues, formClicked } = this.state; if ( formClicked && name === formValues.name && location === formValues.location && picture === formValues.picture && about === formValues.about ) { return this.setState({ originalValues: { name, location, picture, about }, formClicked: false }); } return null; } isFormPristine = () => { const { formValues, originalValues } = this.state; return ( this.state.isPictureUrlValid === false || (Object.keys(originalValues) as Array) .map(key => originalValues[key] === formValues[key]) .every(bool => bool) ); }; handleSubmit = (e: React.FormEvent) => { e.preventDefault(); const { formValues } = this.state; const { submitNewAbout } = this.props; if (this.state.isPictureUrlValid === true && !this.isFormPristine()) { return this.setState({ formClicked: true }, () => submitNewAbout(formValues) ); } else { return false; } }; handleNameChange = (e: React.FormEvent) => { const value = (e.target as HTMLInputElement).value.slice(0); return this.setState(state => ({ formValues: { ...state.formValues, name: value } })); }; handleLocationChange = (e: React.FormEvent) => { const value = (e.target as HTMLInputElement).value.slice(0); return this.setState(state => ({ formValues: { ...state.formValues, location: value } })); }; componentDidMount() { this.validationImage.addEventListener('error', this.errorEvent); this.validationImage.addEventListener('load', this.loadEvent); } componentWillUnmount() { this.validationImage.removeEventListener('load', this.loadEvent); this.validationImage.removeEventListener('error', this.errorEvent); } loadEvent = () => this.setState({ isPictureUrlValid: true }); errorEvent = () => this.setState(state => ({ isPictureUrlValid: state.formValues.picture === '' })); handlePictureChange = (e: React.FormEvent) => { const value = (e.target as HTMLInputElement).value.slice(0); if (isURL(value, { require_protocol: true })) { this.validationImage.src = encodeURI(value); } else { this.setState({ isPictureUrlValid: false }); } this.setState(state => ({ formValues: { ...state.formValues, picture: value } })); }; handleAboutChange = (e: React.FormEvent) => { const value = (e.target as HTMLInputElement).value.slice(0); return this.setState(state => ({ formValues: { ...state.formValues, about: value } })); }; render() { const { formValues: { name, location, picture, about } } = this.state; const { currentTheme, sound, keyboardShortcuts, username, t, toggleNightMode, toggleSoundMode, toggleKeyboardShortcuts } = this.props; return ( <> {t('settings.headings.personal-info')}
{t('settings.labels.name')} {t('settings.labels.location')} {t('settings.labels.picture')} {!this.state.isPictureUrlValid && ( )} {t('settings.labels.about')}
{t('buttons.save')}{' '} {t('settings.headings.personal-info')}
); } } AboutSettings.displayName = 'AboutSettings'; export default withTranslation()(AboutSettings);