From 9b27c41433685ea00f6177833c531ee19de7d7ef Mon Sep 17 00:00:00 2001 From: Tanner Collin Date: Wed, 15 Jan 2020 05:12:00 +0000 Subject: [PATCH] Add UI for instructors to create a new course --- apiserver/apiserver/api/serializers.py | 7 +- webclient/package.json | 1 + webclient/src/App.js | 2 +- webclient/src/Courses.js | 23 ++- webclient/src/Instructor.js | 207 +++++++++++++++++++++++++ webclient/src/light.css | 24 +++ webclient/src/utils.js | 1 + webclient/yarn.lock | 144 ++++++++++++++++- 8 files changed, 388 insertions(+), 21 deletions(-) create mode 100644 webclient/src/Instructor.js diff --git a/apiserver/apiserver/api/serializers.py b/apiserver/apiserver/api/serializers.py index 9a01667..1285da1 100644 --- a/apiserver/apiserver/api/serializers.py +++ b/apiserver/apiserver/api/serializers.py @@ -220,6 +220,8 @@ class SessionListSerializer(SessionSerializer): class CourseSerializer(serializers.ModelSerializer): + name = serializers.CharField() + description = serializers.CharField() class Meta: model = models.Course fields = '__all__' @@ -231,11 +233,6 @@ class CourseDetailSerializer(serializers.ModelSerializer): model = models.Course fields = '__all__' -class AdminCourseSerializer(serializers.ModelSerializer): - class Meta: - model = models.Course - fields = '__all__' - class RegistrationSerializer(RegisterSerializer): diff --git a/webclient/package.json b/webclient/package.json index 06dedad..9311f2f 100644 --- a/webclient/package.json +++ b/webclient/package.json @@ -9,6 +9,7 @@ "moment": "^2.24.0", "react": "^16.12.0", "react-dom": "^16.12.0", + "react-quill": "^1.3.3", "react-router-dom": "^5.1.2", "react-scripts": "3.3.0", "semantic-ui-react": "^0.88.2" diff --git a/webclient/src/App.js b/webclient/src/App.js index bc1cb27..59f8c4f 100644 --- a/webclient/src/App.js +++ b/webclient/src/App.js @@ -150,7 +150,7 @@ function App() { - + diff --git a/webclient/src/Courses.js b/webclient/src/Courses.js index 8437d1f..835d83c 100644 --- a/webclient/src/Courses.js +++ b/webclient/src/Courses.js @@ -3,12 +3,13 @@ import { BrowserRouter as Router, Switch, Route, Link, useParams } from 'react-r import './light.css'; import { Container, Divider, Dropdown, Form, Grid, Header, Icon, Image, Menu, Message, Segment, Table } from 'semantic-ui-react'; import moment from 'moment'; -import { requester } from './utils.js'; +import { isInstructor, requester } from './utils.js'; import { NotFound, PleaseLogin } from './Misc.js'; +import { InstructorCourseList } from './Instructor.js'; export function Courses(props) { const [courses, setCourses] = useState(false); - const { token } = props; + const { token, user } = props; useEffect(() => { requester('/courses/', 'GET', token) @@ -24,6 +25,10 @@ export function Courses(props) {
Courses
+ {isInstructor && + + } + {courses ? @@ -42,7 +47,7 @@ export function Courses(props) { ) : -

None

+ None }
@@ -82,9 +87,13 @@ export function CourseDetail(props) {
{course.name}
Course Description
- {course.description.split('\n').map((x, i) => -

{x}

- )} + {course.is_old ? + course.description.split('\n').map((x, i) => +

{x}

+ ) + : +
+ }
Classes
@@ -112,7 +121,7 @@ export function CourseDetail(props) { ) : -

None

+ None }
diff --git a/webclient/src/Instructor.js b/webclient/src/Instructor.js new file mode 100644 index 0000000..ce25210 --- /dev/null +++ b/webclient/src/Instructor.js @@ -0,0 +1,207 @@ +import React, { useState, useEffect } from 'react'; +import { BrowserRouter as Router, Switch, Route, Link, useParams, useHistory } from 'react-router-dom'; +import ReactQuill from 'react-quill'; +import 'react-quill/dist/quill.snow.css'; +import './light.css'; +import { Button, Container, Checkbox, Divider, Dropdown, Form, Grid, Header, Icon, Image, Label, Menu, Message, Segment, Table } from 'semantic-ui-react'; +import { BasicTable, staticUrl, requester } from './utils.js'; + +function InstructorCourseEditor(props) { + const { input, setInput, error } = props; + + const handleValues = (e, v) => setInput({ ...input, [v.name]: v.value }); + const handleUpload = (e, v) => setInput({ ...input, [v.name]: e.target.files[0] }); + const handleChange = (e) => handleValues(e, e.currentTarget); + const handleCheck = (e, v) => setInput({ ...input, [v.name]: v.checked }); + const handleQuill = (v, d, s, e) => s === 'user' && setInput({ + ...input, + description: v === '


' ? '' : v, + }); + + const makeProps = (name) => ({ + name: name, + onChange: handleChange, + value: input[name] || '', + error: error[name], + }); + + const modules = { + toolbar: [ + [{ 'header': [3, false] }], + ['bold', 'italic', 'underline', 'code'], + [{'list': 'ordered'}, {'list': 'bullet'}], + ['link'], + ['clean'] + ], + }; + + return ( +
+ + + + + + {error.description && + + } + +
+ ); +} + +function InstructorCourseDetail(props) { + const [input, setInput] = useState({ ...props.card }); + const [error, setError] = useState(false); + const [loading, setLoading] = useState(false); + const [success, setSuccess] = useState(false); + const id = props.card.id; + + const handleValues = (e, v) => setInput({ ...input, [v.name]: v.value }); + const handleUpload = (e, v) => setInput({ ...input, [v.name]: e.target.files[0] }); + const handleChange = (e) => handleValues(e, e.currentTarget); + const handleCheck = (e, v) => setInput({ ...input, [v.name]: v.checked }); + + const handleSubmit = (e) => { + setLoading(true); + setSuccess(false); + const data = { ...input, member_id: props.result.member.id }; + requester('/cards/'+id+'/', 'PUT', props.token, data) + .then(res => { + setLoading(false); + setSuccess(true); + setError(false); + setInput(res); + }) + .catch(err => { + setLoading(false); + console.log(err); + setError(err.data); + }); + }; + + const handleDelete = (e) => { + e.preventDefault(); + + requester('/cards/'+id+'/', 'DELETE', props.token) + .then(res => { + setInput(false); + }) + .catch(err => { + console.log(err); + }); + }; + + const statusOptions = [ + { key: '0', text: 'Card Active', value: 'card_active' }, + { key: '1', text: 'Card Blocked', value: 'card_blocked' }, + { key: '2', text: 'Card Inactive', value: 'card_inactive' }, + { key: '3', text: 'Card Member Blocked', value: 'card_member_blocked' }, + ]; + + return ( + input ? + +
+ + + + + + + {success ? 'Saved.' : 'Save'} + + + + Delete + + + + + Notes: {input.notes || 'None'} +
+
+ : + + Deleted card: {props.card.card_number} + + ); +}; + +export function InstructorCourseList(props) { + const { courses, setCourses, token } = props; + const [open, setOpen] = useState(false); + const [input, setInput] = useState({}); + const [error, setError] = useState(false); + const [loading, setLoading] = useState(false); + const [success, setSuccess] = useState(false); + + const handleSubmit = (e) => { + setLoading(true); + setSuccess(false); + const data = { ...input, is_old: false }; + requester('/courses/', 'POST', props.token, data) + .then(res => { + setSuccess(res.id); + setInput({}); + setLoading(false); + setError(false); + setOpen(false); + props.setCourses([ ...courses, res ]); + }) + .catch(err => { + setLoading(false); + console.log(err); + setError(err.data); + }); + }; + + return ( +
+
Instructor Panel
+ + {success &&

Added to bottom of course list! View the course.

} + + {open ? +
+
Add a Course
+ + + + + Submit + + + : + + } +
+ ); +}; + diff --git a/webclient/src/light.css b/webclient/src/light.css index 1ee4eac..7f11aba 100644 --- a/webclient/src/light.css +++ b/webclient/src/light.css @@ -63,6 +63,30 @@ body { padding-bottom: 24rem; } +.course-editor { + margin-bottom: 1rem; +} + +.ql-container { + height: 30rem !important; + font-size: inherit !important; + font-family: inherit !important; +} + +.ql-editor p, +.ql-editor ol, +.ql-editor ul, +.ql-editor pre, +.ql-editor blockquote, +.ql-editor h1, +.ql-editor h2, +.ql-editor h3, +.ql-editor h4, +.ql-editor h5, +.ql-editor h6 { + margin-bottom: 1rem !important; +} + .footer { margin-top: -20rem; diff --git a/webclient/src/utils.js b/webclient/src/utils.js index 8a5fdc3..1279072 100644 --- a/webclient/src/utils.js +++ b/webclient/src/utils.js @@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react'; import { Table } from 'semantic-ui-react'; export const isAdmin = (user) => user.is_staff || user.member.is_director || user.member.is_staff; +export const isInstructor = (user) => isAdmin(user) || user.member.is_staff; export const siteUrl = window.location.protocol + '//' + window.location.hostname; export const apiUrl = window.location.protocol + '//api.' + window.location.hostname; diff --git a/webclient/yarn.lock b/webclient/yarn.lock index 8d1e607..3f76ea0 100644 --- a/webclient/yarn.lock +++ b/webclient/yarn.lock @@ -1355,6 +1355,13 @@ resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8" integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw== +"@types/quill@1.3.10": + version "1.3.10" + resolved "https://registry.yarnpkg.com/@types/quill/-/quill-1.3.10.tgz#dc1f7b6587f7ee94bdf5291bc92289f6f0497613" + integrity sha512-IhW3fPW+bkt9MLNlycw8u8fWb7oO7W5URC9MfZYHBlA24rex9rs23D5DETChu1zvgVdc5ka64ICjJOgQMr6Shw== + dependencies: + parchment "^1.1.2" + "@types/react-dom@*": version "16.9.4" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.4.tgz#0b58df09a60961dcb77f62d4f1832427513420df" @@ -1856,7 +1863,7 @@ arrify@^1.0.1: resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= -asap@~2.0.6: +asap@~2.0.3, asap@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= @@ -2672,6 +2679,11 @@ clone-deep@^4.0.1: kind-of "^6.0.2" shallow-clone "^3.0.0" +clone@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= + co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -2905,6 +2917,11 @@ core-js-pure@^3.0.0: resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.4.7.tgz#c998e1892da9949200c7452cbd33c0df95be9f54" integrity sha512-Am3uRS8WCdTFA3lP7LtKR0PxgqYzjAMGKXaZKSNSC/8sqU0Wfq8R/YzoRs2rqtOVEunfgH+0q3O0BKOg0AvjPw== +core-js@^1.0.0: + version "1.2.7" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" + integrity sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY= + core-js@^2.4.0: version "2.6.10" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.10.tgz#8a5b8391f8cc7013da703411ce5b585706300d7f" @@ -2972,6 +2989,15 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: safe-buffer "^5.0.1" sha.js "^2.4.8" +create-react-class@^15.6.0: + version "15.6.3" + resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.6.3.tgz#2d73237fb3f970ae6ebe011a9e66f46dbca80036" + integrity sha512-M+/3Q6E6DLO6Yx3OwrWjwHBnvfXXYA7W+dFjt/ZDBemHO1DDZhsalX/NUtnTYclN6GfnBDRh4qRHjcDHmlJBJg== + dependencies: + fbjs "^0.8.9" + loose-envify "^1.3.1" + object-assign "^4.1.1" + create-react-context@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/create-react-context/-/create-react-context-0.3.0.tgz#546dede9dc422def0d3fc2fe03afe0bc0f4f7d8c" @@ -3631,6 +3657,13 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= +encoding@^0.1.11: + version "0.1.12" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + integrity sha1-U4tm8+5izRq1HsMjgp0flIDHS+s= + dependencies: + iconv-lite "~0.4.13" + end-of-stream@^1.0.0, end-of-stream@^1.1.0: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" @@ -3956,6 +3989,11 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= +eventemitter3@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-2.0.3.tgz#b5e1079b59fb5e1ba2771c0a993be060a58c99ba" + integrity sha1-teEHm1n7XhuidxwKmTvgYKWMmbo= + eventemitter3@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.0.tgz#d65176163887ee59f386d64c82610b696a4a74eb" @@ -4092,7 +4130,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" -extend@~3.0.2: +extend@^3.0.2, extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== @@ -4135,6 +4173,11 @@ fast-deep-equal@^2.0.1: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= +fast-diff@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.1.2.tgz#4b62c42b8e03de3f848460b639079920695d0154" + integrity sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig== + fast-glob@^2.0.2: version "2.2.7" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d" @@ -4178,6 +4221,19 @@ fb-watchman@^2.0.0: dependencies: bser "^2.0.0" +fbjs@^0.8.9: + version "0.8.17" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd" + integrity sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90= + dependencies: + core-js "^1.0.0" + isomorphic-fetch "^2.1.1" + loose-envify "^1.0.0" + object-assign "^4.1.0" + promise "^7.1.1" + setimmediate "^1.0.5" + ua-parser-js "^0.7.18" + figgy-pudding@^3.5.1: version "3.5.1" resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" @@ -4937,7 +4993,7 @@ https-browserify@^1.0.0: resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= -iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: +iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -5394,7 +5450,7 @@ is-root@2.1.0: resolved "https://registry.yarnpkg.com/is-root/-/is-root-2.1.0.tgz#809e18129cf1129644302a4f8544035d51984a9c" integrity sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg== -is-stream@^1.1.0: +is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= @@ -5460,6 +5516,14 @@ isobject@^3.0.0, isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= +isomorphic-fetch@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" + integrity sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk= + dependencies: + node-fetch "^1.0.1" + whatwg-fetch ">=0.10.0" + isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" @@ -6268,7 +6332,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -"lodash@>=3.5 <5", lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.5: +"lodash@>=3.5 <5", lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.17.5: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== @@ -6736,6 +6800,14 @@ no-case@^2.2.0: dependencies: lower-case "^1.1.1" +node-fetch@^1.0.1: + version "1.7.3" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" + integrity sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ== + dependencies: + encoding "^0.1.11" + is-stream "^1.0.1" + node-forge@0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579" @@ -7260,6 +7332,11 @@ param-case@2.1.x: dependencies: no-case "^2.2.0" +parchment@^1.1.2, parchment@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/parchment/-/parchment-1.1.4.tgz#aeded7ab938fe921d4c34bc339ce1168bc2ffde5" + integrity sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg== + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -8238,6 +8315,13 @@ promise-inflight@^1.0.1: resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= +promise@^7.1.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== + dependencies: + asap "~2.0.3" + promise@^8.0.3: version "8.0.3" resolved "https://registry.yarnpkg.com/promise/-/promise-8.0.3.tgz#f592e099c6cddc000d538ee7283bb190452b0bf6" @@ -8253,7 +8337,7 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.3" -prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2: +prop-types@^15.5.10, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -8370,6 +8454,27 @@ querystringify@^2.1.1: resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e" integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA== +quill-delta@^3.6.2: + version "3.6.3" + resolved "https://registry.yarnpkg.com/quill-delta/-/quill-delta-3.6.3.tgz#b19fd2b89412301c60e1ff213d8d860eac0f1032" + integrity sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg== + dependencies: + deep-equal "^1.0.1" + extend "^3.0.2" + fast-diff "1.1.2" + +quill@^1.2.6: + version "1.3.7" + resolved "https://registry.yarnpkg.com/quill/-/quill-1.3.7.tgz#da5b2f3a2c470e932340cdbf3668c9f21f9286e8" + integrity sha512-hG/DVzh/TiknWtE6QmWAF/pxoZKYxfe3J/d/+ShUWkDvvkZQVTPeVmUJVu1uE6DDooC4fWTiCLh84ul89oNz5g== + dependencies: + clone "^2.1.1" + deep-equal "^1.0.1" + eventemitter3 "^2.0.3" + extend "^3.0.2" + parchment "^1.1.4" + quill-delta "^3.6.2" + raf@^3.4.1: version "3.4.1" resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" @@ -8459,6 +8564,11 @@ react-dev-utils@^10.0.0: strip-ansi "5.2.0" text-table "0.2.0" +react-dom-factories@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/react-dom-factories/-/react-dom-factories-1.0.2.tgz#eb7705c4db36fb501b3aa38ff759616aa0ff96e0" + integrity sha1-63cFxNs2+1AbOqOP91lhaqD/luA= + react-dom@^16.12.0: version "16.12.0" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.12.0.tgz#0da4b714b8d13c2038c9396b54a92baea633fe11" @@ -8492,6 +8602,19 @@ react-popper@^1.3.4: typed-styles "^0.0.7" warning "^4.0.2" +react-quill@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/react-quill/-/react-quill-1.3.3.tgz#95b8e088ad4e4acc6c79c2f85bdc0460eebe08eb" + integrity sha512-T9RubLaWJ8gCfp7sOqmFupjiTiEp/EdGqhCG+PWGKc5UHiK6xIWNKWYsOHHEhQ+sZCKs8u/DPx47gc1VfFmcLg== + dependencies: + "@types/quill" "1.3.10" + "@types/react" "*" + create-react-class "^15.6.0" + lodash "^4.17.4" + prop-types "^15.5.10" + quill "^1.2.6" + react-dom-factories "^1.0.0" + react-router-dom@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.1.2.tgz#06701b834352f44d37fbb6311f870f84c76b9c18" @@ -9208,7 +9331,7 @@ set-value@^2.0.0, set-value@^2.0.1: is-plain-object "^2.0.3" split-string "^3.0.1" -setimmediate@^1.0.4: +setimmediate@^1.0.4, setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= @@ -10061,6 +10184,11 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= +ua-parser-js@^0.7.18: + version "0.7.21" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.21.tgz#853cf9ce93f642f67174273cc34565ae6f308777" + integrity sha512-+O8/qh/Qj8CgC6eYBVBykMrNtp5Gebn4dlGD/kKXVkJNDwyrAwSIqwz8CDf+tsAIWVycKcku6gIXJ0qwx/ZXaQ== + uglify-js@3.4.x: version "3.4.10" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.10.tgz#9ad9563d8eb3acdfb8d38597d2af1d815f6a755f" @@ -10475,7 +10603,7 @@ whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3, whatwg-encoding@^1.0.5: dependencies: iconv-lite "0.4.24" -whatwg-fetch@^3.0.0: +whatwg-fetch@>=0.10.0, whatwg-fetch@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb" integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==