mirror of
https://github.com/rjNemo/devbook_ts
synced 2026-06-06 02:36:39 +00:00
refactor: EditProfile folder
This commit is contained in:
parent
b3faf506f2
commit
80895656b6
3 changed files with 358 additions and 319 deletions
|
|
@ -1,319 +0,0 @@
|
|||
import React, {FC, useState} from 'react';
|
||||
import {Link} from 'react-router-dom';
|
||||
import Routes from '../constants/routes';
|
||||
// Redux
|
||||
import {enhance} from '../store/firebase';
|
||||
import {WithFirebaseProps} from 'react-redux-firebase';
|
||||
// Style
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
|
||||
import {
|
||||
faTwitter,
|
||||
faFacebook,
|
||||
faYoutube,
|
||||
faLinkedin,
|
||||
faInstagram,
|
||||
} from '@fortawesome/free-brands-svg-icons';
|
||||
import FormHeader from '../components/FormHeader';
|
||||
import Alert from '../components/Alert';
|
||||
import Statuses from '../constants/statuses';
|
||||
// Form
|
||||
import useForm from '../hooks';
|
||||
import getGithubRepos from '../services/github';
|
||||
// Typing
|
||||
import Dev from '../models/Dev';
|
||||
import User from '../models/User';
|
||||
import Links, {parseLink, getGithubLink} from '../types/Links';
|
||||
import IAlert, {formAlert} from '../types/Alert';
|
||||
|
||||
interface FormData {
|
||||
status: string;
|
||||
company: string;
|
||||
website: string;
|
||||
location: string;
|
||||
skills: string;
|
||||
github: string;
|
||||
bio: string;
|
||||
facebook: string;
|
||||
linkedin: string;
|
||||
instagram: string;
|
||||
twitter: string;
|
||||
youtube: string;
|
||||
}
|
||||
|
||||
interface IProps extends Dev, WithFirebaseProps<User> {}
|
||||
|
||||
/**
|
||||
* Form to update dev's personal information.
|
||||
*/
|
||||
const EditProfile: FC<IProps> = ({
|
||||
firebase,
|
||||
status,
|
||||
skills,
|
||||
company,
|
||||
links,
|
||||
location,
|
||||
bio,
|
||||
github,
|
||||
}) => {
|
||||
const [showLinks, setShowLinks] = useState(false);
|
||||
const [alert, setAlert] = useState<IAlert>(formAlert);
|
||||
|
||||
const initFormData = {
|
||||
status: status ?? 'Developer',
|
||||
company: company,
|
||||
location: location ?? '',
|
||||
bio: bio ?? '',
|
||||
skills: skills?.toString() ?? '',
|
||||
website: links?.website ?? '',
|
||||
github: github ?? '',
|
||||
facebook: links?.facebook ?? '',
|
||||
linkedin: links?.linkedin ?? '',
|
||||
instagram: links?.instagram ?? '',
|
||||
twitter: links?.twitter ?? '',
|
||||
youtube: links?.youtube ?? '',
|
||||
};
|
||||
|
||||
const {formData, handleChange} = useForm<FormData>(initFormData);
|
||||
|
||||
/** construct profile object from formData */
|
||||
const makeProfile = async ({
|
||||
status,
|
||||
company,
|
||||
location,
|
||||
bio,
|
||||
website,
|
||||
instagram,
|
||||
facebook,
|
||||
linkedin,
|
||||
twitter,
|
||||
github,
|
||||
youtube,
|
||||
skills,
|
||||
}: FormData) => {
|
||||
const newLinks: Links = {
|
||||
website: parseLink(website),
|
||||
instagram: parseLink(instagram),
|
||||
facebook: parseLink(facebook),
|
||||
linkedin: parseLink(linkedin),
|
||||
twitter: parseLink(twitter),
|
||||
github: getGithubLink(github),
|
||||
youtube: parseLink(youtube),
|
||||
};
|
||||
const newSkills: string[] = skills?.split(',');
|
||||
const newRepos = await getGithubRepos(github);
|
||||
return {
|
||||
status,
|
||||
company,
|
||||
location,
|
||||
bio,
|
||||
github,
|
||||
links: newLinks,
|
||||
skills: newSkills,
|
||||
repos: newRepos,
|
||||
};
|
||||
};
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
const updatedDev = await makeProfile(formData);
|
||||
try {
|
||||
firebase.updateProfile(updatedDev, {useSet: true, merge: true});
|
||||
setAlert({
|
||||
show: true,
|
||||
color: 'success',
|
||||
text:
|
||||
'Profile successfully updated. You may go back to your dashboard.',
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
setAlert({...alert, show: true});
|
||||
}
|
||||
};
|
||||
|
||||
const isDisabled: boolean = formData.status === '' || formData.skills === '';
|
||||
|
||||
const toggleSocialLinks = () => setShowLinks(!showLinks);
|
||||
return (
|
||||
<section className="container">
|
||||
<FormHeader
|
||||
title="Edit your profile"
|
||||
lead="Let's get some information to make your profile stand out"
|
||||
/>
|
||||
|
||||
<form className="form" onSubmit={handleSubmit}>
|
||||
<div className="form-group">
|
||||
<select
|
||||
name="status"
|
||||
required
|
||||
onChange={handleChange}
|
||||
defaultValue={formData.status}
|
||||
>
|
||||
<option disabled>* Select Professional Status</option>
|
||||
{Statuses.map((s: string, i: number) => (
|
||||
<option value={s} key={i}>
|
||||
{s}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<small className="form-text">
|
||||
Give us an idea of where you are at in your career
|
||||
</small>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Company"
|
||||
name="company"
|
||||
value={formData.company}
|
||||
// value={variable}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<small className="form-text">
|
||||
Could be your own company or one you work for
|
||||
</small>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Website"
|
||||
name="website"
|
||||
value={formData.website}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<small className="form-text">
|
||||
Could be your own or a company website
|
||||
</small>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Location"
|
||||
name="location"
|
||||
value={formData.location}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<small className="form-text">
|
||||
City & state suggested (eg. Boston, MA)
|
||||
</small>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="* Skills"
|
||||
name="skills"
|
||||
required
|
||||
value={formData.skills}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<small className="form-text">
|
||||
Please use comma separated values (eg. HTML,CSS,JavaScript,PHP)
|
||||
</small>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Github Username"
|
||||
name="github"
|
||||
value={formData.github}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<small className="form-text">
|
||||
If you want your latest repos and a Github link, include your
|
||||
username
|
||||
</small>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<textarea
|
||||
placeholder="A short bio of yourself"
|
||||
name="bio"
|
||||
value={formData.bio}
|
||||
onChange={handleChange}
|
||||
></textarea>
|
||||
<small className="form-text">Tell us a little about yourself</small>
|
||||
</div>
|
||||
|
||||
<div className="my-2">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-light"
|
||||
onClick={toggleSocialLinks}
|
||||
>
|
||||
{showLinks ? 'Hide' : 'Add'} Social Network Links
|
||||
</button>
|
||||
<span>Optional</span>
|
||||
</div>
|
||||
|
||||
{showLinks && (
|
||||
<>
|
||||
<div className="form-group social-input">
|
||||
<FontAwesomeIcon icon={faFacebook} size="2x" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Facebook URL"
|
||||
name="facebook"
|
||||
value={formData.facebook}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="form-group social-input">
|
||||
<FontAwesomeIcon icon={faInstagram} size="2x" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Instagram URL"
|
||||
name="instagram"
|
||||
value={formData.instagram}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="form-group social-input">
|
||||
<FontAwesomeIcon icon={faLinkedin} size="2x" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Linkedin URL"
|
||||
name="linkedin"
|
||||
value={formData.linkedin}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="form-group social-input">
|
||||
<FontAwesomeIcon icon={faTwitter} size="2x" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Twitter URL"
|
||||
name="twitter"
|
||||
value={formData.twitter}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="form-group social-input">
|
||||
<FontAwesomeIcon icon={faYoutube} size="2x" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="YouTube URL"
|
||||
name="youtube"
|
||||
value={formData.youtube}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{alert.show && <Alert text={alert.text} color={alert.color} />}
|
||||
<input
|
||||
type="submit"
|
||||
className="btn btn-primary my-1"
|
||||
value="Submit"
|
||||
disabled={isDisabled}
|
||||
/>
|
||||
<Link to={Routes.DASHBOARD} className="btn btn-light my-1">
|
||||
Go Back
|
||||
</Link>
|
||||
</form>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default enhance(EditProfile);
|
||||
211
src/pages/EditProfile/Form.tsx
Normal file
211
src/pages/EditProfile/Form.tsx
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
import React, {FC} from 'react';
|
||||
// Routing
|
||||
import {Link} from 'react-router-dom';
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
|
||||
import {
|
||||
faFacebook,
|
||||
faInstagram,
|
||||
faLinkedin,
|
||||
faTwitter,
|
||||
faYoutube,
|
||||
} from '@fortawesome/free-brands-svg-icons';
|
||||
import {IProfileForm} from '.';
|
||||
|
||||
import Routes from '../../constants/routes';
|
||||
import Statuses from '../../constants/statuses';
|
||||
|
||||
interface IProps {
|
||||
showLinks: boolean;
|
||||
isDisabled: boolean;
|
||||
formData: IProfileForm;
|
||||
handleSubmit: (e: React.FormEvent<HTMLFormElement>) => void;
|
||||
handleChange: (
|
||||
e: React.ChangeEvent<
|
||||
HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement
|
||||
>,
|
||||
) => void;
|
||||
toggleSocialLinks: () => void;
|
||||
}
|
||||
|
||||
const EditProfileForm: FC<IProps> = ({
|
||||
showLinks,
|
||||
handleSubmit,
|
||||
formData,
|
||||
handleChange,
|
||||
isDisabled,
|
||||
toggleSocialLinks,
|
||||
}) => (
|
||||
<form className="form" onSubmit={handleSubmit}>
|
||||
<div className="form-group">
|
||||
<select
|
||||
name="status"
|
||||
required
|
||||
onChange={handleChange}
|
||||
defaultValue={formData.status}
|
||||
>
|
||||
<option disabled>* Select Professional Status</option>
|
||||
{Statuses.map((s: string, i: number) => (
|
||||
<option value={s} key={i}>
|
||||
{s}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<small className="form-text">
|
||||
Give us an idea of where you are at in your career
|
||||
</small>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Company"
|
||||
name="company"
|
||||
value={formData.company}
|
||||
// value={variable}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<small className="form-text">
|
||||
Could be your own company or one you work for
|
||||
</small>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Website"
|
||||
name="website"
|
||||
value={formData.website}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<small className="form-text">
|
||||
Could be your own or a company website
|
||||
</small>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Location"
|
||||
name="location"
|
||||
value={formData.location}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<small className="form-text">
|
||||
City & state suggested (eg. Boston, MA)
|
||||
</small>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="* Skills"
|
||||
name="skills"
|
||||
required
|
||||
value={formData.skills}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<small className="form-text">
|
||||
Please use comma separated values (eg. HTML,CSS,JavaScript,PHP)
|
||||
</small>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Github Username"
|
||||
name="github"
|
||||
value={formData.github}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<small className="form-text">
|
||||
If you want your latest repos and a Github link, include your username
|
||||
</small>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<textarea
|
||||
placeholder="A short bio of yourself"
|
||||
name="bio"
|
||||
value={formData.bio}
|
||||
onChange={handleChange}
|
||||
></textarea>
|
||||
<small className="form-text">Tell us a little about yourself</small>
|
||||
</div>
|
||||
|
||||
<div className="my-2">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-light"
|
||||
onClick={toggleSocialLinks}
|
||||
>
|
||||
{showLinks ? 'Hide' : 'Add'} Social Network Links
|
||||
</button>
|
||||
<span>Optional</span>
|
||||
</div>
|
||||
|
||||
{showLinks && (
|
||||
<>
|
||||
<div className="form-group social-input">
|
||||
<FontAwesomeIcon icon={faFacebook} size="2x" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Facebook URL"
|
||||
name="facebook"
|
||||
value={formData.facebook}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="form-group social-input">
|
||||
<FontAwesomeIcon icon={faInstagram} size="2x" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Instagram URL"
|
||||
name="instagram"
|
||||
value={formData.instagram}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="form-group social-input">
|
||||
<FontAwesomeIcon icon={faLinkedin} size="2x" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Linkedin URL"
|
||||
name="linkedin"
|
||||
value={formData.linkedin}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="form-group social-input">
|
||||
<FontAwesomeIcon icon={faTwitter} size="2x" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Twitter URL"
|
||||
name="twitter"
|
||||
value={formData.twitter}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="form-group social-input">
|
||||
<FontAwesomeIcon icon={faYoutube} size="2x" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="YouTube URL"
|
||||
name="youtube"
|
||||
value={formData.youtube}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<input
|
||||
type="submit"
|
||||
className="btn btn-primary my-1"
|
||||
value="Submit"
|
||||
disabled={isDisabled}
|
||||
/>
|
||||
<Link to={Routes.DASHBOARD} className="btn btn-light my-1">
|
||||
Go Back
|
||||
</Link>
|
||||
</form>
|
||||
);
|
||||
|
||||
export default EditProfileForm;
|
||||
147
src/pages/EditProfile/index.tsx
Normal file
147
src/pages/EditProfile/index.tsx
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
import React, {FC, useState} from 'react';
|
||||
// Redux
|
||||
import {enhance} from '../../store/firebase';
|
||||
import {WithFirebaseProps} from 'react-redux-firebase';
|
||||
// Style
|
||||
import FormHeader from '../../components/FormHeader';
|
||||
import Alert from '../../components/Alert';
|
||||
// Form
|
||||
import useForm from '../../hooks';
|
||||
import getGithubRepos from '../../services/github';
|
||||
// Typing
|
||||
import Dev from '../../models/Dev';
|
||||
import User from '../../models/User';
|
||||
import Links, {parseLink, getGithubLink} from '../../types/Links';
|
||||
import IAlert, {formAlert} from '../../types/Alert';
|
||||
import EditProfileForm from './Form';
|
||||
|
||||
export interface IProfileForm {
|
||||
status: string;
|
||||
company: string;
|
||||
website: string;
|
||||
location: string;
|
||||
skills: string;
|
||||
github: string;
|
||||
bio: string;
|
||||
facebook: string;
|
||||
linkedin: string;
|
||||
instagram: string;
|
||||
twitter: string;
|
||||
youtube: string;
|
||||
}
|
||||
|
||||
interface IProps extends Dev, WithFirebaseProps<User> {}
|
||||
|
||||
/**
|
||||
* Form to update dev's personal information.
|
||||
*/
|
||||
const EditProfile: FC<IProps> = ({
|
||||
firebase,
|
||||
status,
|
||||
skills,
|
||||
company,
|
||||
links,
|
||||
location,
|
||||
bio,
|
||||
github,
|
||||
}) => {
|
||||
const [showLinks, setShowLinks] = useState(false);
|
||||
const [alert, setAlert] = useState<IAlert>(formAlert);
|
||||
|
||||
const initFormData = {
|
||||
status: status ?? 'Developer',
|
||||
company: company,
|
||||
location: location ?? '',
|
||||
bio: bio ?? '',
|
||||
skills: skills?.toString() ?? '',
|
||||
website: links?.website ?? '',
|
||||
github: github ?? '',
|
||||
facebook: links?.facebook ?? '',
|
||||
linkedin: links?.linkedin ?? '',
|
||||
instagram: links?.instagram ?? '',
|
||||
twitter: links?.twitter ?? '',
|
||||
youtube: links?.youtube ?? '',
|
||||
};
|
||||
|
||||
const {formData, handleChange} = useForm<IProfileForm>(initFormData);
|
||||
|
||||
/** construct profile object from formData */
|
||||
const makeProfile = async ({
|
||||
status,
|
||||
company,
|
||||
location,
|
||||
bio,
|
||||
website,
|
||||
instagram,
|
||||
facebook,
|
||||
linkedin,
|
||||
twitter,
|
||||
github,
|
||||
youtube,
|
||||
skills,
|
||||
}: IProfileForm) => {
|
||||
const newLinks: Links = {
|
||||
website: parseLink(website),
|
||||
instagram: parseLink(instagram),
|
||||
facebook: parseLink(facebook),
|
||||
linkedin: parseLink(linkedin),
|
||||
twitter: parseLink(twitter),
|
||||
github: getGithubLink(github),
|
||||
youtube: parseLink(youtube),
|
||||
};
|
||||
const newSkills: string[] = skills?.split(',');
|
||||
const newRepos = await getGithubRepos(github);
|
||||
return {
|
||||
status,
|
||||
company,
|
||||
location,
|
||||
bio,
|
||||
github,
|
||||
links: newLinks,
|
||||
skills: newSkills,
|
||||
repos: newRepos,
|
||||
};
|
||||
};
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
const updatedDev = await makeProfile(formData);
|
||||
try {
|
||||
firebase.updateProfile(updatedDev, {useSet: true, merge: true});
|
||||
setAlert({
|
||||
show: true,
|
||||
color: 'success',
|
||||
text:
|
||||
'Profile successfully updated. You may go back to your dashboard.',
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
setAlert({...alert, show: true});
|
||||
}
|
||||
};
|
||||
|
||||
const isDisabled: boolean = formData.status === '' || formData.skills === '';
|
||||
|
||||
const toggleSocialLinks = () => setShowLinks(!showLinks);
|
||||
|
||||
return (
|
||||
<section className="container">
|
||||
<FormHeader
|
||||
title="Edit your profile"
|
||||
lead="Let's get some information to make your profile stand out"
|
||||
/>
|
||||
|
||||
{alert.show && <Alert text={alert.text} color={alert.color} />}
|
||||
<EditProfileForm
|
||||
formData={formData}
|
||||
handleChange={handleChange}
|
||||
handleSubmit={handleSubmit}
|
||||
isDisabled={isDisabled}
|
||||
toggleSocialLinks={toggleSocialLinks}
|
||||
showLinks={showLinks}
|
||||
/>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default enhance(EditProfile);
|
||||
Loading…
Reference in a new issue