address-controls
4 years ago
address-fields
4 years ago
email-controls
4 years ago
utils
2 years ago
content.js
2 weeks ago
index.js
4 years ago
style.scss
2 weeks ago
content.js
244 lines
| 1 | import Heading from '../../components/heading'; |
| 2 | import Divider from '../../components/divider'; |
| 3 | import AvatarControl from '../../components/avatar-control'; |
| 4 | import FieldRow from '../../components/field-row'; |
| 5 | import SelectControl from '../../components/select-control'; |
| 6 | import TextControl from '../../components/text-control'; |
| 7 | import RadioControl from '../../components/radio-control'; |
| 8 | import Button from '../../components/button'; |
| 9 | import {updateProfileWithAPI, updatePasswordWithAPI} from './utils'; |
| 10 | import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; |
| 11 | |
| 12 | import EmailControls from './email-controls'; |
| 13 | import AddressControls from './address-controls'; |
| 14 | |
| 15 | import {Fragment, useState, useEffect} from 'react'; |
| 16 | import {useSelector} from 'react-redux'; |
| 17 | import {__} from '@wordpress/i18n'; |
| 18 | |
| 19 | import './style.scss'; |
| 20 | |
| 21 | const Content = () => { |
| 22 | const id = useSelector((state) => state.id); |
| 23 | const storedProfile = useSelector((state) => state.profile); |
| 24 | const [isUpdating, setIsUpdating] = useState(false); |
| 25 | const [updated, setUpdated] = useState(false); |
| 26 | |
| 27 | useEffect(() => { |
| 28 | setAvatarFile(null); |
| 29 | setAvatarUrl(storedProfile.avatarUrl); |
| 30 | }, [storedProfile]); |
| 31 | |
| 32 | const [titlePrefix, setTitlePrefix] = useState(storedProfile.titlePrefix); |
| 33 | const titlePrefixOptions = [ |
| 34 | { |
| 35 | value: 'Mr.', |
| 36 | label: __('Mr.', 'give'), |
| 37 | }, |
| 38 | { |
| 39 | value: 'Ms.', |
| 40 | label: __('Ms.', 'give'), |
| 41 | }, |
| 42 | { |
| 43 | value: 'Mrs.', |
| 44 | label: __('Mrs.', 'give'), |
| 45 | }, |
| 46 | ]; |
| 47 | |
| 48 | const [avatarFile, setAvatarFile] = useState(null); |
| 49 | const [avatarUrl, setAvatarUrl] = useState(storedProfile.avatarUrl); |
| 50 | |
| 51 | const [firstName, setFirstName] = useState(storedProfile.firstName); |
| 52 | const [lastName, setLastName] = useState(storedProfile.lastName); |
| 53 | |
| 54 | const [company, setCompany] = useState(storedProfile.company); |
| 55 | |
| 56 | const [primaryEmail, setPrimaryEmail] = useState(storedProfile.emails ? storedProfile.emails.primary : ''); |
| 57 | |
| 58 | const reducedAdditionalEmails = storedProfile.emails |
| 59 | ? Object.keys(storedProfile.emails).reduce((newArray, key) => { |
| 60 | if (key !== 'primary') { |
| 61 | newArray.push(storedProfile.emails[key]); |
| 62 | } |
| 63 | return newArray; |
| 64 | }, []) |
| 65 | : []; |
| 66 | |
| 67 | const [additionalEmails, setAdditionalEmails] = useState(reducedAdditionalEmails); |
| 68 | |
| 69 | const [primaryAddress, setPrimaryAddress] = useState( |
| 70 | storedProfile.addresses && storedProfile.addresses.billing ? storedProfile.addresses.billing[0] : null |
| 71 | ); |
| 72 | |
| 73 | const reducedAdditionalAddresses = |
| 74 | storedProfile.addresses && storedProfile.addresses.billing |
| 75 | ? Object.values(storedProfile.addresses.billing).reduce((newArray, address, index) => { |
| 76 | if (index !== 0) { |
| 77 | newArray.push(address); |
| 78 | } |
| 79 | return newArray; |
| 80 | }, []) |
| 81 | : []; |
| 82 | |
| 83 | const [additionalAddresses, setAdditionalAddresses] = useState(reducedAdditionalAddresses); |
| 84 | |
| 85 | const [isAnonymous, setIsAnonymous] = useState(storedProfile.isAnonymous); |
| 86 | const anonymousOptions = [ |
| 87 | { |
| 88 | value: '0', |
| 89 | label: __('Public - show my donations publicly', 'give'), |
| 90 | }, |
| 91 | { |
| 92 | value: '1', |
| 93 | label: __('Private - only organization admins can view my info', 'give'), |
| 94 | }, |
| 95 | ]; |
| 96 | |
| 97 | const [newPassword, setNewPassword] = useState(''); |
| 98 | const [passwordUpdated, setPasswordUpdated] = useState(false); |
| 99 | const handlePasswordUpdate = async () => { |
| 100 | if (!newPassword.trim()) { |
| 101 | return; |
| 102 | } |
| 103 | updatePasswordWithAPI(newPassword); |
| 104 | setNewPassword(''); |
| 105 | setPasswordUpdated(true); |
| 106 | }; |
| 107 | |
| 108 | useEffect(() => { |
| 109 | setUpdated(false); |
| 110 | }, [ |
| 111 | titlePrefix, |
| 112 | firstName, |
| 113 | lastName, |
| 114 | company, |
| 115 | primaryEmail, |
| 116 | additionalEmails, |
| 117 | primaryAddress, |
| 118 | additionalAddresses, |
| 119 | isAnonymous, |
| 120 | ]); |
| 121 | |
| 122 | useEffect(() => { |
| 123 | if (avatarFile !== null) { |
| 124 | setUpdated(false); |
| 125 | } |
| 126 | }, [avatarFile]); |
| 127 | |
| 128 | const handleUpdate = async () => { |
| 129 | setIsUpdating(true); |
| 130 | await updateProfileWithAPI({ |
| 131 | titlePrefix, |
| 132 | firstName, |
| 133 | lastName, |
| 134 | company, |
| 135 | primaryEmail, |
| 136 | additionalEmails, |
| 137 | primaryAddress, |
| 138 | additionalAddresses, |
| 139 | avatarFile, |
| 140 | isAnonymous, |
| 141 | id, |
| 142 | }); |
| 143 | setUpdated(true); |
| 144 | setIsUpdating(false); |
| 145 | }; |
| 146 | |
| 147 | return ( |
| 148 | <Fragment> |
| 149 | <Heading>{__('Profile Information', 'give')}</Heading> |
| 150 | <Divider /> |
| 151 | <AvatarControl url={avatarUrl} file={avatarFile} onChange={(value) => setAvatarFile(value)} /> |
| 152 | <FieldRow> |
| 153 | <SelectControl |
| 154 | label={__('Prefix', 'give')} |
| 155 | value={titlePrefix} |
| 156 | onChange={(value) => setTitlePrefix(value)} |
| 157 | options={titlePrefixOptions} |
| 158 | placeholder="--" |
| 159 | width="120px" |
| 160 | isClearable={true} |
| 161 | /> |
| 162 | <TextControl |
| 163 | label={__('First Name', 'give')} |
| 164 | value={firstName} |
| 165 | onChange={(value) => setFirstName(value)} |
| 166 | icon="user" |
| 167 | /> |
| 168 | <TextControl |
| 169 | label={__('Last Name', 'give')} |
| 170 | value={lastName} |
| 171 | onChange={(value) => setLastName(value)} |
| 172 | /> |
| 173 | </FieldRow> |
| 174 | <TextControl label={__('Company', 'give')} value={company} onChange={(value) => setCompany(value)} /> |
| 175 | <EmailControls |
| 176 | primaryEmail={primaryEmail} |
| 177 | additionalEmails={additionalEmails} |
| 178 | onChangePrimaryEmail={(value) => setPrimaryEmail(value)} |
| 179 | onChangeAdditionalEmails={(value) => setAdditionalEmails(value)} |
| 180 | /> |
| 181 | <AddressControls |
| 182 | primaryAddress={primaryAddress} |
| 183 | additionalAddresses={additionalAddresses} |
| 184 | onChangePrimaryAddress={(value) => setPrimaryAddress(value)} |
| 185 | onChangeAdditionalAddresses={(value) => setAdditionalAddresses(value)} |
| 186 | /> |
| 187 | <Heading>{__('Additional Info', 'give')}</Heading> |
| 188 | <Divider /> |
| 189 | <RadioControl |
| 190 | label={__('Anonymous Giving', 'give')} |
| 191 | description={__( |
| 192 | 'This will prevent your avatar, first name, donation comments, and other information from appearing publicly on this organization’s website.', |
| 193 | 'give' |
| 194 | )} |
| 195 | options={anonymousOptions} |
| 196 | onChange={(value) => setIsAnonymous(value)} |
| 197 | value={isAnonymous} |
| 198 | /> |
| 199 | <Button onClick={() => handleUpdate()}> |
| 200 | {updated ? ( |
| 201 | <Fragment> |
| 202 | {__('Updated', 'give')} <FontAwesomeIcon icon="check" fixedWidth /> |
| 203 | </Fragment> |
| 204 | ) : ( |
| 205 | <Fragment> |
| 206 | {__('Update Profile', 'give')}{' '} |
| 207 | <FontAwesomeIcon |
| 208 | className={isUpdating ? 'give-donor-dashboard__edit-profile-spinner' : ''} |
| 209 | icon={isUpdating ? 'spinner' : 'save'} |
| 210 | fixedWidth |
| 211 | /> |
| 212 | </Fragment> |
| 213 | )} |
| 214 | </Button> |
| 215 | |
| 216 | <Heading>{__('Update Password', 'give')}</Heading> |
| 217 | <Divider /> |
| 218 | <TextControl |
| 219 | type="password" |
| 220 | label={__('New Password', 'give')} |
| 221 | value={newPassword} |
| 222 | onChange={(value) => setNewPassword(value)} |
| 223 | /> |
| 224 | <Button onClick={() => handlePasswordUpdate()} disabled={!newPassword.trim()}> |
| 225 | {passwordUpdated ? ( |
| 226 | <Fragment> |
| 227 | {__('Updated', 'give')} <FontAwesomeIcon icon="check" fixedWidth /> |
| 228 | </Fragment> |
| 229 | ) : ( |
| 230 | <Fragment> |
| 231 | {__('Update Password', 'give')}{' '} |
| 232 | <FontAwesomeIcon |
| 233 | className={isUpdating ? 'give-donor-dashboard__edit-profile-spinner' : ''} |
| 234 | icon={isUpdating ? 'spinner' : 'save'} |
| 235 | fixedWidth |
| 236 | /> |
| 237 | </Fragment> |
| 238 | )} |
| 239 | </Button> |
| 240 | </Fragment> |
| 241 | ); |
| 242 | }; |
| 243 | export default Content; |
| 244 |