- switched to useSelector

- implemented skills section
This commit is contained in:
Amruth Pillai
2020-07-08 22:26:27 +05:30
parent 70866420e5
commit a1931f5e36
23 changed files with 316 additions and 191 deletions

View File

@ -1,22 +1,20 @@
import React, { useContext } from "react";
import { Helmet } from "react-helmet";
import ResumeContext from "../../../contexts/ResumeContext";
import { useSelector } from "../../../contexts/ResumeContext";
import TemplateContext from "../../../contexts/TemplateContext";
import Onyx from "../../../templates/Onyx";
import styles from "./Artboard.module.css";
const Artboard = () => {
const { blocks, colors } = useContext(TemplateContext);
const { state } = useContext(ResumeContext);
const state = useSelector((state) => state),
{ id, name } = state;
return (
<div>
<Helmet>
<title>{state.name} | Reactive Resume</title>
<link
rel="canonical"
href={`https://rxresu.me/app/builder/${state.id}`}
/>
<title>{name} | Reactive Resume</title>
<link rel="canonical" href={`https://rxresu.me/app/builder/${id}`} />
</Helmet>
<div id="artboard" className={styles.container}>

View File

@ -1,12 +1,9 @@
import React, { Fragment, useContext } from "react";
import ResumeContext from "../../../contexts/ResumeContext";
import React, { Fragment } from "react";
import sections from "../../../data/leftSections";
import LeftNavbar from "./LeftNavbar";
import styles from "./LeftSidebar.module.css";
const LeftSidebar = () => {
const { state } = useContext(ResumeContext);
return (
<div className="flex">
<LeftNavbar />
@ -14,7 +11,7 @@ const LeftSidebar = () => {
<div className={styles.container}>
{sections.map(({ id, name, event, component: Component }) => (
<Fragment key={id}>
<Component id={id} name={name} event={event} state={state} />
<Component id={id} name={name} event={event} />
<hr />
</Fragment>
))}

View File

@ -3,6 +3,7 @@ import moment from "moment";
import React, { useContext } from "react";
import { MdAdd } from "react-icons/md";
import ModalContext from "../../../contexts/ModalContext";
import { useSelector } from "../../../contexts/ResumeContext";
import Button from "../../shared/Button";
import EmptyList from "./EmptyList";
import styles from "./List.module.css";
@ -10,7 +11,6 @@ import ListItem from "./ListItem";
const List = ({
path,
items,
title,
titlePath,
subtitle,
@ -19,6 +19,7 @@ const List = ({
textPath,
event,
}) => {
const items = useSelector((state) => get(state, path, []));
const { emitter } = useContext(ModalContext);
const handleAdd = () => emitter.emit(event);

View File

@ -1,8 +1,8 @@
import { Menu, MenuItem } from "@material-ui/core";
import React, { useContext, useState } from "react";
import React, { useState } from "react";
import { IoIosArrowDown, IoIosArrowUp } from "react-icons/io";
import { MdMoreVert } from "react-icons/md";
import ResumeContext from "../../../contexts/ResumeContext";
import { useDispatch } from "../../../contexts/ResumeContext";
import styles from "./ListItem.module.css";
const ListItem = ({
@ -16,7 +16,7 @@ const ListItem = ({
onEdit,
}) => {
const [anchorEl, setAnchorEl] = useState(null);
const { dispatch } = useContext(ResumeContext);
const dispatch = useDispatch();
const handleClick = (event) => setAnchorEl(event.currentTarget);

View File

@ -1,11 +1,9 @@
import { get } from "lodash";
import React from "react";
import Heading from "../../shared/Heading";
import List from "../lists/List";
const Awards = ({ id, name, event, state }) => {
const path = `${id}.items`;
const items = get(state, path, []);
return (
<section>
@ -13,7 +11,6 @@ const Awards = ({ id, name, event, state }) => {
<List
path={path}
items={items}
event={event}
titlePath="title"
subtitlePath="awarder"

View File

@ -1,11 +1,9 @@
import { get } from "lodash";
import React from "react";
import Heading from "../../shared/Heading";
import List from "../lists/List";
const Certifications = ({ id, name, event, state }) => {
const path = `${id}.items`;
const items = get(state, path, []);
return (
<section>
@ -13,7 +11,6 @@ const Certifications = ({ id, name, event, state }) => {
<List
path={path}
items={items}
event={event}
titlePath="title"
subtitlePath="issuer"

View File

@ -1,11 +1,9 @@
import { get } from "lodash";
import React from "react";
import Heading from "../../shared/Heading";
import List from "../lists/List";
const Education = ({ id, name, event, state }) => {
const path = `${id}.items`;
const items = get(state, path, []);
return (
<section>
@ -13,7 +11,6 @@ const Education = ({ id, name, event, state }) => {
<List
path={path}
items={items}
event={event}
titlePath="institution"
textPath="field"

View File

@ -1,69 +1,45 @@
import React, { useContext, useRef } from "react";
import { MdFileUpload } from "react-icons/md";
import StorageContext from "../../../contexts/StorageContext";
import { handleKeyDown } from "../../../utils";
import React from "react";
import Heading from "../../shared/Heading";
import Input from "../../shared/Input";
import styles from "./Profile.module.css";
import PhotoUpload from "../../shared/PhotoUpload";
const Profile = () => {
const fileInputRef = useRef(null);
const { uploadPhotograph } = useContext(StorageContext);
const handleIconClick = () => {
fileInputRef.current.click();
};
const handleImageUpload = (e) => {
const file = e.target.files[0];
uploadPhotograph(file);
};
return (
<section>
<Heading>Profile</Heading>
<div className="flex items-center">
<div
role="button"
tabIndex="0"
className={styles.circle}
onClick={handleIconClick}
onKeyDown={(e) => handleKeyDown(e, handleIconClick)}
>
<MdFileUpload size="22px" />
<input
type="file"
ref={fileInputRef}
className="hidden"
onChange={handleImageUpload}
/>
</div>
<Input label="Photograph" className="pl-6" path="profile.photograph" />
</div>
<PhotoUpload />
<div className="grid grid-cols-2 gap-6">
<Input label="First Name" path="profile.firstName" />
<Input label="Last Name" path="profile.lastName" />
<Input name="firstName" label="First Name" path="profile.firstName" />
<Input name="lastName" label="Last Name" path="profile.lastName" />
</div>
<Input label="Subtitle" path="profile.subtitle" />
<Input name="subtitle" label="Subtitle" path="profile.subtitle" />
<hr />
<Input label="Address Line 1" path="profile.address.line1" />
<Input label="Address Line 2" path="profile.address.line2" />
<Input
name="addressLine1"
label="Address Line 1"
path="profile.address.line1"
/>
<Input
name="addressLine2"
label="Address Line 2"
path="profile.address.line2"
/>
<div className="grid grid-cols-2 gap-6">
<Input label="City" path="profile.address.city" />
<Input label="Pincode" path="profile.address.pincode" />
<Input name="city" label="City" path="profile.address.city" />
<Input name="pincode" label="Pincode" path="profile.address.pincode" />
</div>
<hr />
<Input label="Phone Number" path="profile.phone" />
<Input label="Website" path="profile.website" />
<Input label="Email Address" path="profile.email" />
<Input name="phone" label="Phone Number" path="profile.phone" />
<Input name="website" label="Website" path="profile.website" />
<Input name="email" label="Email Address" path="profile.email" />
</section>
);
};

View File

@ -0,0 +1,17 @@
import React from "react";
import Heading from "../../shared/Heading";
import List from "../lists/List";
const Skills = ({ id, name, event }) => {
const path = `${id}.items`;
return (
<section>
<Heading>{name}</Heading>
<List path={path} event={event} titlePath="name" subtitlePath="level" />
</section>
);
};
export default Skills;

View File

@ -1,11 +1,9 @@
import { get } from "lodash";
import React from "react";
import Heading from "../../shared/Heading";
import List from "../lists/List";
const Social = ({ id, name, event, state }) => {
const Social = ({ id, name, event }) => {
const path = `${id}.items`;
const items = get(state, path, []);
return (
<section>
@ -13,7 +11,6 @@ const Social = ({ id, name, event, state }) => {
<List
path={path}
items={items}
event={event}
titlePath="network"
subtitlePath="username"

View File

@ -1,23 +1,15 @@
import { get } from "lodash";
import React from "react";
import Heading from "../../shared/Heading";
import List from "../lists/List";
const Work = ({ id, name, event, state }) => {
const path = `${id}.items`;
const items = get(state, path, []);
return (
<section>
<Heading>{name}</Heading>
<List
path={path}
items={items}
event={event}
titlePath="company"
textPath="summary"
/>
<List path={path} event={event} titlePath="company" textPath="summary" />
</section>
);
};

View File

@ -1,9 +1,9 @@
import cx from "classnames";
import { get, isFunction } from "lodash";
import React, { useContext } from "react";
import React, { useMemo } from "react";
import { MdClose } from "react-icons/md";
import { v4 as uuidv4 } from "uuid";
import ResumeContext from "../../contexts/ResumeContext";
import { useDispatch, useSelector } from "../../contexts/ResumeContext";
import { handleKeyDown } from "../../utils";
import styles from "./Input.module.css";
@ -11,8 +11,8 @@ const Input = ({
name,
path,
label,
value,
error,
value,
onBlur,
touched,
checked,
@ -25,86 +25,109 @@ const Input = ({
type = "text",
}) => {
const uuid = uuidv4();
const { state, dispatch } = useContext(ResumeContext);
const stateValue = useSelector((state) => get(state, path));
const dispatch = useDispatch();
const inputProps = (path) => ({
value: get(state, path) || "",
onChange: (e) => {
dispatch({
type: "on_input",
payload: {
path,
value: e.target.value,
},
});
},
});
value = value || stateValue;
onChange = isFunction(onChange)
? onChange
: (e) => {
dispatch({
type: "on_input",
payload: {
path,
value: e.target.value,
},
});
};
return (
<div className={cx(styles.container, className)}>
<label htmlFor={uuid}>
<span>
{label}{" "}
{isRequired && (
<span className="opacity-75 font-normal lowercase">(Required)</span>
)}
</span>
{type === "textarea" ? (
<div className="flex flex-col">
<textarea
id={uuid}
rows="4"
name={name}
type={type}
value={value}
onBlur={onBlur}
checked={checked}
onChange={onChange}
placeholder={placeholder}
{...(path && inputProps(path))}
/>
<p className="mt-2 text-sm opacity-75">
This text block supports{" "}
<a
href="https://www.markdownguide.org/basic-syntax/"
className="text-blue-600"
target="blank"
>
markdown
</a>
.
</p>
</div>
) : (
<div className="relative grid items-center">
<input
id={uuid}
name={name}
type={type}
value={value}
onBlur={onBlur}
checked={checked}
onChange={onChange}
placeholder={placeholder}
{...(path && inputProps(path))}
/>
{showDeleteItemButton && isFunction(onDeleteItem) && (
<MdClose
size="16px"
tabIndex="0"
onClick={onDeleteItem}
onKeyDown={(e) => handleKeyDown(e, onDeleteItem)}
className="absolute right-0 cursor-pointer opacity-50 hover:opacity-75 mx-4"
/>
return useMemo(
() => (
<div className={cx(styles.container, className)}>
<label htmlFor={uuid}>
<span>
{label}{" "}
{isRequired && (
<span className="opacity-75 font-normal lowercase">
(Required)
</span>
)}
</div>
)}
{error && touched && <p>{error}</p>}
</label>
</div>
</span>
{type === "text" && (
<div className="relative grid items-center">
<input
id={uuid}
name={name}
type={type}
value={value}
onBlur={onBlur}
checked={checked}
onChange={onChange}
placeholder={placeholder}
/>
{showDeleteItemButton && isFunction(onDeleteItem) && (
<MdClose
size="16px"
tabIndex="0"
onClick={onDeleteItem}
onKeyDown={(e) => handleKeyDown(e, onDeleteItem)}
className="absolute right-0 cursor-pointer opacity-50 hover:opacity-75 mx-4"
/>
)}
</div>
)}
{type === "textarea" && (
<div className="flex flex-col">
<textarea
id={uuid}
rows="4"
name={name}
type={type}
value={value}
onBlur={onBlur}
checked={checked}
onChange={onChange}
placeholder={placeholder}
/>
<p className="mt-2 text-sm opacity-75">
This text block supports{" "}
<a
href="https://www.markdownguide.org/basic-syntax/"
className="text-blue-600"
target="blank"
>
markdown
</a>
.
</p>
</div>
)}
{error && touched && <p>{error}</p>}
</label>
</div>
),
[
checked,
className,
error,
isRequired,
label,
name,
onBlur,
onChange,
onDeleteItem,
placeholder,
showDeleteItemButton,
touched,
type,
uuid,
value,
]
);
};

View File

@ -0,0 +1,50 @@
import React, { useContext, useRef } from "react";
import { MdFileUpload } from "react-icons/md";
import StorageContext from "../../contexts/StorageContext";
import { handleKeyDown } from "../../utils";
import Input from "./Input";
import styles from "./PhotoUpload.module.css";
const PhotoUpload = () => {
const fileInputRef = useRef(null);
const { uploadPhotograph } = useContext(StorageContext);
const handleIconClick = () => {
fileInputRef.current.click();
};
const handleImageUpload = (e) => {
const file = e.target.files[0];
uploadPhotograph(file);
};
return (
<div className="flex items-center">
<div
role="button"
tabIndex="0"
className={styles.circle}
onClick={handleIconClick}
onKeyDown={(e) => handleKeyDown(e, handleIconClick)}
>
<MdFileUpload size="22px" />
<input
name="file"
type="file"
ref={fileInputRef}
className="hidden"
onChange={handleImageUpload}
/>
</div>
<Input
name="photograph"
label="Photograph"
className="pl-6"
path="profile.photograph"
/>
</div>
);
};
export default PhotoUpload;