Skip to content

Commit

Permalink
create rich text editor
Browse files Browse the repository at this point in the history
  • Loading branch information
cidneyweng committed Mar 17, 2021
1 parent f8aa8bb commit 42b1f30
Show file tree
Hide file tree
Showing 8 changed files with 290 additions and 87 deletions.
151 changes: 89 additions & 62 deletions client/src/components/LessonPage.js
Original file line number Diff line number Diff line change
@@ -1,116 +1,143 @@
import React, { useState, useEffect } from 'react';
import { FiEdit } from 'react-icons/fi';
import ContentEditable from 'react-contenteditable';

import { EditorState, convertToRaw, convertFromRaw } from 'draft-js';
import TextEditor from './TextEditor';
import 'draft-js/dist/Draft.css';
import '../stylesheets/LessonPage.css';

const LessonPage = props => {
const { id, ismentor } = props;

const [editMode, setEditMode] = useState(false);
const [title, setTitle] = useState('');
const [descriptionHTML, setDescriptionHTML] = useState('');
const [resourcesHTML, setResourcesHTML] = useState('');
const [labHTML, setLabHTML] = useState('');
const [exitTicketHTML, setExitTicketHTML] = useState('');
const [descriptionState, setDescriptionState] = useState(EditorState.createEmpty());
const [resourcesState, setResourcesState] = useState(EditorState.createEmpty());
const [labState, setLabState] = useState(EditorState.createEmpty());
const [exitTicketState, setExitTicketState] = useState(EditorState.createEmpty());
const [oldDescriptionState, setOldDescriptionState] = useState(
EditorState.createEmpty(),
);
const [oldResourcesState, setOldResourcesState] = useState(EditorState.createEmpty());
const [oldLabState, setOldLabState] = useState(EditorState.createEmpty());
const [oldExitTicketState, setOldExitTicketState] = useState(EditorState.createEmpty());

useEffect(() => {
fetch('/api/v1/lessons/' + id + '?id=' + id)
.then(res => res.json())
.then(lesson => {
setTitle(lesson[0].title);
setDescriptionHTML(lesson[0].descriptionHTML);
setResourcesHTML(lesson[0].resourcesHTML);
setLabHTML(lesson[0].labHTML);
setExitTicketHTML(lesson[0].exitTicketHTML);
if (lesson[0].description_state) {
const content = convertFromRaw(lesson[0].description_state);
setDescriptionState(EditorState.createWithContent(content));
setOldDescriptionState(EditorState.createWithContent(content));
}
if (lesson[0].resources_state) {
const content = convertFromRaw(lesson[0].resources_state);
setResourcesState(EditorState.createWithContent(content));
setOldResourcesState(EditorState.createWithContent(content));
}
if (lesson[0].lab_state) {
const content = convertFromRaw(lesson[0].lab_state);
setLabState(EditorState.createWithContent(content));
setOldLabState(EditorState.createWithContent(content));
}
if (lesson[0].exit_ticket_state) {
const content = convertFromRaw(lesson[0].exit_ticket_state);
setExitTicketState(EditorState.createWithContent(content));
setOldExitTicketState(EditorState.createWithContent(content));
}
});
}, [id]);

const handleDescriptionChange = evt => {
setDescriptionHTML(evt.target.value);
const handleDescriptionChange = newState => {
setDescriptionState(newState);
console.log(newState);
};

const handleResourcesChange = newState => {
setResourcesState(newState);
};

const handleResourcesChange = evt => {
setResourcesHTML(evt.target.value);
const handleLabChange = newState => {
setLabState(newState);
};

const handleLabChange = evt => {
setLabHTML(evt.target.value);
const handleExitTicketChange = newState => {
setExitTicketState(newState);
};

const handleExitTicketChange = evt => {
setExitTicketHTML(evt.target.value);
const cancelChanges = () => {
setDescriptionState(oldDescriptionState);
setResourcesState(oldResourcesState);
setLabState(oldLabState);
setExitTicketState(oldExitTicketState);
setEditMode(false);
};

const saveChanges = () => {
fetch('/api/v1/lessons/updatePage', {
method: 'POST',
body: JSON.stringify({
lessonId: id,
editedDescriptionHTML: descriptionHTML,
editedResourcesHTML: resourcesHTML,
editedLabHTML: labHTML,
editedExitTicketHTML: exitTicketHTML,
editedDescriptionState: convertToRaw(descriptionState.getCurrentContent()),
editedResourcesState: convertToRaw(resourcesState.getCurrentContent()),
editedLabState: convertToRaw(labState.getCurrentContent()),
editedExitTicketState: convertToRaw(exitTicketState.getCurrentContent()),
}),
headers: new Headers({
'Content-Type': 'application/json',
}),
}).then(setEditMode(false));
};

let maybeEditButton;
if (ismentor) {
maybeEditButton = (
<button className="editButton" onClick={() => setEditMode(true)} type="button">
<FiEdit size="42" />
</button>
);
}
let maybeSaveButton;
let editing = '';
if (editMode) {
maybeSaveButton = (
<button className="saveButton" onClick={saveChanges} type="button">
Save
</button>
);
editing = 'editing';
}
return (
<div className="page">
<div className="lessonPageContainer">
<div className="title-container">
<h1 className="lessonPageTitle">{title}</h1>
{maybeEditButton}
{ismentor && (
<button
className="editButton"
onClick={() => setEditMode(true)}
type="button"
>
<FiEdit size="42" />
</button>
)}
</div>
<ContentEditable
className={'textBox ' + editing}
html={descriptionHTML}
disabled={!editMode}
onChange={handleDescriptionChange} // handle innerHTML change
<TextEditor
editorState={descriptionState}
editMode={editMode}
onChange={handleDescriptionChange}
/>
<h2 className="textTitle"> Lesson Resources </h2>
<ContentEditable
className={'textBox ' + editing}
html={resourcesHTML}
disabled={!editMode}
onChange={handleResourcesChange} // handle innerHTML change
<TextEditor
editorState={resourcesState}
editMode={editMode}
onChange={handleResourcesChange}
/>
<h2 className="textTitle"> Lab </h2>
<ContentEditable
className={'textBox ' + editing}
html={labHTML}
disabled={!editMode}
onChange={handleLabChange} // handle innerHTML change
<TextEditor
editorState={labState}
editMode={editMode}
onChange={handleLabChange}
/>
<h2 className="textTitle"> Exit Ticket </h2>
<ContentEditable
className={'textBox ' + editing}
html={exitTicketHTML}
disabled={!editMode}
onChange={handleExitTicketChange} // handle innerHTML change
<TextEditor
editorState={exitTicketState}
editMode={editMode}
onChange={handleExitTicketChange}
/>
{maybeSaveButton}
{editMode && (
<div className="buttonsContainer">
<button className="cancelButton" onClick={cancelChanges} type="button">
Cancel
</button>
<button className="saveButton" onClick={saveChanges} type="button">
Save
</button>
</div>
)}
</div>
</div>
);
Expand Down
57 changes: 57 additions & 0 deletions client/src/components/TextEditor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React from 'react';
import { Editor, RichUtils } from 'draft-js';
import 'draft-js/dist/Draft.css';

const TextEditor = props => {
const { editMode, editorState, onChange } = props;

const editing = editMode ? 'editing' : '';

const handleKeyCommand = command => {
const newState = RichUtils.handleKeyCommand(editorState, command);
if (newState) {
onChange(newState);
}
};

const onUnderlineClick = () => {
onChange(RichUtils.toggleInlineStyle(editorState, 'UNDERLINE'));
};

const onBoldClick = () => {
onChange(RichUtils.toggleInlineStyle(editorState, 'BOLD'));
};

const onItalicClick = () => {
onChange(RichUtils.toggleInlineStyle(editorState, 'ITALIC'));
};

return (
<div className={'textBox ' + editing}>
{editMode && (
<>
<div>
<button className="editorButton" onClick={onUnderlineClick}>
U
</button>
<button className="editorButton" onClick={onBoldClick}>
<b>B</b>
</button>
<button className="editorButton" onClick={onItalicClick}>
<em>I</em>
</button>
</div>
<div className="line" />
</>
)}
<Editor
editorState={editorState}
handleKeyCommand={handleKeyCommand}
onChange={onChange}
readOnly={!editMode}
/>
</div>
);
};

export default TextEditor;
71 changes: 59 additions & 12 deletions client/src/stylesheets/LessonPage.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,12 @@
.page {
background-color: #e9f4fb;
height: 100%;
padding-bottom: 200px;
min-height: 100vh;
padding: 100px 120px 150px 120px;
}

.lessonPageContainer {
width: 85%;
position: relative;
left: 100px;
top: 100px;
}

.title-container {
Expand Down Expand Up @@ -51,32 +49,81 @@ h1,

.textBox {
min-height: 45px;
width: 90%;
padding: 10px;
width: 100%;
margin-bottom: 20px;
font-size: 16px;
border-radius: 5px;
}

.editing {
background-color: #ffffff;
padding: 10px;
box-shadow: 0px -4px 0px #d2edfc;
}

.saveButton {
font-family: Lato, sans-serif;
background-color: #2e64bc;
color: #ffffff;
.buttonsContainer {
margin-top: 30px;
position: relative;
left: 85%;
float: right;
font-size: 18px;
font-family: Lato, sans-serif;
}

.saveButton {
background-color: #2e64bc;
color: #ffffff;
border: none;
padding: 8px 22px;
border-radius: 5px;
}

.saveButton:hover {
.cancelButton {
background-color: #ededed;
border: none;
padding: 8px 22px;
border-radius: 5px;
margin-right: 15px;
}

.saveButton:hover,
.cancelButton:hover {
cursor: pointer;
opacity: 0.8;
}

.editorButton {
background: none;
outline: none;
border: none;
border-radius: 3px;
cursor: pointer;
width: 30px;
height: 30px;
color: grey;
}

.editorButton:hover {
background: #e9f4fb;
}

.DraftEditor-root {
padding-top: 10px;
padding-bottom: 10px;
}

.line {
border-top: 1px solid #ededed;
margin-top: 10px;
}

@media (max-width: 767px) {
.page {
padding: 100px 100px 150px 100px;
}
}

@media (max-width: 600px) {
.page {
padding: 100px 50px 100px 50px;
}
}
2 changes: 1 addition & 1 deletion client/src/stylesheets/NavBar.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
width: 100%;
position: fixed;
background: white;
z-index: 1;
z-index: 2;
}

.profile-logo {
Expand Down
Loading

0 comments on commit 42b1f30

Please sign in to comment.