tinymce react plugin registration does not work - javascript

Was trying to register a custom plugin in tinymce but ever attempt failed.
Created a plugin using yoman generator build it and reference in the project
Created a plugin using yoman generator directly reference in the project without building
Also tried the below approach is still doesn't work
import { FC, RefObject, useLayoutEffect, useRef } from 'react'
import { Editor } from '#tinymce/tinymce-react';
import { plugins, toolbar, quickBarsInsertToolbar } from './config';
import tinymce, { Editor as TinyMCEEditor, PluginManager } from 'tinymce';
import './index.css'
// import '../../plugins/dropdown-plugin/dist/dropdown-plugin/plugin.min.js';
const TinymceEditor: FC = () => {
const editorRef = useRef<TinyMCEEditor | null>(null);
const log = () => {
if (editorRef.current) {
console.log(editorRef.current.getContent());
}
};
useLayoutEffect(() => {
tinymce.PluginManager.add("dropdown-plugin", function (n, t) { n.ui.registry.addButton("dropdown-plugin", { text: "dropdown-plugin button", onAction: function () { n.setContent("<p>content added from dropdown-plugin</p>") } }) })
}, [])
return (
<div
className='tinymce_editor'
>
<Editor
onInit={(evt, editor) => editorRef.current = editor}
init={{
height: 500,
plugins:['dropdown-plugin'],
toolbar:'dropdown-plugin'
}}
/>
<button onClick={log}>Log editor content</button>
</div>
)
}
export default TinymceEditor;
Gives this error

Finally Working now
import { FC, useLayoutEffect, useRef } from 'react'
import { Editor } from '#tinymce/tinymce-react';
import { plugins, toolbar, quickBarsInsertToolbar } from './config';
import { Editor as TinyMCEEditor } from 'tinymce';
import './index.css'
import { registerPlugins } from './plugin/register-plugins';
const TinymceEditor: FC = () => {
const editorRef = useRef<TinyMCEEditor | null>(null);
const log = () => {
if (editorRef.current) {
console.log(editorRef.current.getContent());
}
};
useLayoutEffect(() => {
registerPlugins()
}, [])
return (
<div
className='tinymce_editor'
>
<Editor
onInit={(evt, editor) => editorRef.current = editor}
init={{
height: 500,
plugins: plugins,
quickbars_insert_toolbar: quickBarsInsertToolbar,
toolbar: toolbar
}}
/>
<button onClick={log}>Log editor content</button>
</div>
)
}
export default TinymceEditor;
import { customQuickBarButton } from './customQuickBarButton';
import tinymce from 'tinymce';
import { customToolBarButtonMenu } from './customToolBarButtonMenu';
export const registerPlugins = () => {
tinymce.PluginManager.add(
'custom-quickbar-button-plugin',
customQuickBarButton
);
tinymce.PluginManager.add(
'custom-toolbar-button-menu-plugin',
customToolBarButtonMenu
);
};
import ReactDOM from 'react-dom';
import { Editor } from 'tinymce';
export const customToolBarButtonMenu = (editor: Editor) => {
editor.ui.registry.addMenuButton('custom-toolbar-button-menu-plugin', {
text: 'Custom Menu',
icon: 'language',
fetch: callback => {
var items = [
{
type: 'menuitem',
text: 'Menu Item 1',
icon: 'arrow-right',
onAction: () => {
editor.insertContent(' <em>You clicked menu item 1!</em> ');
},
},
{
type: 'menuitem',
text: 'Menu Item 2',
icon: 'user',
onAction: () => {
const div = document.createElement('div');
ReactDOM.render(
<div>
<span>Signature with image</span>
<img src="https://i.picsum.photos/id/532/200/200.jpg?hmac=PPwpqfjXOagQmhd_K7H4NXyA4B6svToDi1IbkDW2Eos" />
</div>,
div
);
editor.selection.setNode(div);
},
},
];
callback(items as any);
},
});
};

Related

useRef undefined error using nextjs and remirror editor component

I'm using NextJS and Remirror Editor plugin. I get an error that setContent is undefined on the index page where the editor is loaded. I want to add an "external" button after the Component is loaded to exit the text. The component is dynamically externally loaded. I'm really unsure how to make the external button/text change to work.
Index.tsx:
import { NextPage, GetStaticProps } from 'next';
import dynamic from 'next/dynamic';
import { WysiwygEditor } from '#remirror/react-editors/wysiwyg';
import React, { useRef, useEffect } from 'react';
const TextEditor = dynamic( () => import('../text-editor'), { ssr: false } );
import natural from "natural";
export interface EditorRef {
setContent: (content: any) => void;
}
type Props = {
aaa:string
bbb:string
}
const Home: NextPage< Props > = (props) => {
//hook call ref to use editor externally
const ref = useRef<EditorRef | null>(null);
const {aaa,bbb} = props;
return (
<>
<ul>
{aaa} </ul>
Next.js Home Page
<TextEditor ref={ref} />
{
useEffect(()=>{
ref.current!.setContent({content: "testing the text has changed"})
},[])}
<button onClick={() => ref.current.setContent({content: "testing the text has changed"})}>Set another text button 2</button>
</>
);
};
var stringWordNet = "";
export const getStaticProps = async ():Promise<GetStaticPropsResult<Props>> => {
var wordnet = new natural.WordNet();
wordnet.lookup('node', function(results) {
stringWordNet = String(results[0].synonyms[1]);
});
return {
props:{
aaa:stringWordNet,
bbb:"bbb"
}
}
};
export default Home;
text-editor.tsx
import 'remirror/styles/all.css';
import { useEffect, useState, forwardRef, Ref, useImperativeHandle, useRef } from 'react';
import { BoldExtension,
ItalicExtension,
selectionPositioner,
UnderlineExtension, MentionAtomExtension } from 'remirror/extensions';
import { cx } from '#remirror/core';
import {
EditorComponent,
FloatingWrapper,
MentionAtomNodeAttributes,
Remirror,
useMentionAtom,
useRemirror, ThemeProvider, useRemirrorContext
} from '#remirror/react';
import { css } from "#emotion/css";
const styles = css`
background-color: white;
color: #101010;
border: 1px solid #ccc;
border-radius: 4px;
padding: 4px;
`;
const ALL_USERS = [
{ id: 'wordnetSuggestion1', label: 'NotreSuggestion1' },
{ id: 'wordnetSuggestion2', label: 'NotreSuggestion2' },
{ id: 'wordnetSuggestion3', label: 'NotreSuggestion3' },
{ id: 'wordnetSuggestion4', label: 'NotreSuggestion4' },
{ id: 'wordnetSuggestion5', label: 'NotreSuggestion5' },
];
const MentionSuggestor: React.FC = () => {
return (
<FloatingWrapper positioner={selectionPositioner} placement='bottom-start'>
<div>
{
ALL_USERS.map((option, index) => (
<li> {option.label}</li>
))
}
</div>
</FloatingWrapper>
);
};
const DOC = {
type: 'doc',
content: [
{
type: 'paragraph',
content: [
{
type: 'text',
text: 'New content',
},
],
},
],
};
//Start Imperative Handle Here
export interface EditorRef {
setContent: (content: any) => void;
}
const ImperativeHandle = forwardRef((_: unknown, ref: Ref<EditorRef>) => {
const { setContent } = useRemirrorContext({
autoUpdate: true,
});
// Expose content handling to outside
useImperativeHandle(ref, () => ({ setContent }));
return <></>;
});
//Make content to show.
const TextEditor = forwardRef((_: unknown, ref: Ref<EditorRef>) => {
const editorRef = useRef<EditorRef | null>(null);
const { manager, state, getContext } = useRemirror({
extensions: () => [
new MentionAtomExtension()
],
content: '<p>I love Remirror</p>',
selection: 'start',
stringHandler: 'html',
});
return (
<>
<button
onMouseDown={(event) => event.preventDefault()}
onClick={() => editorRef.current!.setContent(DOC)}
></button>
<div className='remirror-theme'>
<Remirror manager={manager} initialContent={state}>
<EditorComponent />
<MentionSuggestor />
<ImperativeHandle ref={editorRef} />
</Remirror>
</div>
</>
);
});
export default TextEditor;

How to test a presentation component using React Testing Library

I have a Tabs component here.
Tabs.jsx
import React from "react";
import { Radio } from "antd";
function Tabs({ modes, selectedMode, handleChange }) {
return (
<Radio.Group onChange={handleChange} value={selectedMode}>
{modes.map((opt) => (
<Radio.Button key={opt.id} value={opt.id}>
{opt.label}
</Radio.Button>
))}
</Radio.Group>
);
}
export default Tabs;
App.jsx
import "./styles.css";
import Tabs from "./Tabs";
import React, { useState } from "react";
import "antd/dist/antd.css";
const MODES = [
{ id: 1, label: "Label 1" },
{ id: 2, label: "Label 2" }
];
export default function App() {
const [mode, setMode] = useState(MODES[0]);
const handleModeChange = (e) => {
setMode(e.target.value);
};
return (
<Tabs modes={MODES} selectedMode={mode} handleChange={handleModeChange} />
);
}
Here's the Codesandbox
https://codesandbox.io/s/vigilant-tesla-tcj4p8
Currently I try to test for the Tabs component using Jest and React Testing Library.
There are 2 ways I can think of:
Test the styles change after user interaction
describe('Tabs', () => {
it('works correctly', () => {
const MOCK_MODES = [
{ id: 1, label: "Label 1" },
{ id: 2, label: "Label 2" }
];
const [mockSelected, setMockSelected] = useState(MOCK_MODES[0].id)
const mockHandleModeChange = (e) => {
setMode(e.target.value);
};
const { container, getByText } = render(<Tabs modes={MOCK_MODES} handleChange={mockHandleModeChange}/>);
expect(container.firstChild).toHaveClass('ant-radio-button-wrapper-checked')
expect(container.secondChild).not.toHaveClass('ant-radio-button-wrapper-checked')
const item = getByText('Label 2');
fireEvent.click(item);
expect(container.firstChild).not.toHaveClass('ant-radio-button-wrapper-checked')
expect(container.secondChild).toHaveClass('ant-radio-button-wrapper-checked')
});
});
Just check whether the handleChange event is fired, with black-box testing.
describe('Tabs', () => {
it('works correctly', () => {
const MOCK_MODES = [
{ id: 1, label: "Label 1" },
{ id: 2, label: "Label 2" }
];
const mockSelected = 1;
const mockHandleModeChange = (e) => jest.fn();
const { getByText } = render(<Tabs modes={MOCK_MODES} handleChange={mockHandleModeChange}/>);
const item = getByText('Label 2');
fireEvent.click(item);
expect(mockHandleModeChange).toHaveBeenCalledTimes(1);
});
});
Which one should be the best? Or any better suggestions?

pass graphql data from parent to child in gatsby.js

for the sake of not repeating my self, I want to make a component like this
import React, { Suspense } from 'react'
// import PropTypes from 'prop-types'
import { graphql, Link } from "gatsby"
import Img from "gatsby-image"
import Layout from "../components/layout"
// import SEO from "../components/seo"
// import Pager from "../components/pager"
import { lazy } from '#loadable/component'
import loadable from '#loadable/component'
const Pagination = loadable(() => import('../components/page/pagination'))
const Pager = lazy(() => import('../components/pager'))
const Dropdown = lazy(() => import('../components/dropdown/index'))
class PaginationNew extends React.Component {
render() {
const data = this.props
const posts = this.props.data.allCockpitPost.edges
const { pageContext } = this.props
// mama, pageContext
return (
<>
<div className="paginate-name-div">
<h1 className="paginate-h1">Semua postingan</h1>
{typeof window !== 'undefined' && (
<Suspense fallback={<div>Loading...</div>}>
<Dropdown pageContext={pageContext} />
</Suspense>
)}
</div>
<ul className="paginate-ul">
{posts.map(({ node, }) => {
return (
<li className="paginate-li" key={node.id}>
<Link to={`/${node.title.slug}`} className="paginate-link">
<div className="paginate-div1" >
<Img crossOrigin="true" imgStyle={{ objectFit: "unset", }} loading="lazy" fadeIn={false} fluid={node.image.value.childImageSharp.fluid} alt={node.title.value} className="paginate-img" />
</div>
<div className="paginate-div2">
<h3 dangerouslySetInnerHTML={{ __html: node.title.value }} className="paginate-h3" />
<p className="paginate-written"> Ditulis Oleh {node.content.value.childMarkdownRemark.frontmatter.author} Pada {node.date.value}</p>
<div dangerouslySetInnerHTML={{ __html: node.description.value.childMarkdownRemark.excerpt }} className="paginate-div3">
</div>
</div>
</Link>
</li>
)
})}
</ul>
{typeof window !== 'undefined' && (
<Suspense fallback={<div>Loading...</div>}>
<Pager pageContext={pageContext} />
</Suspense>
)}
</>
)
}
}
export default PaginationNew
that used to belong in this code
import React, { Suspense } from 'react'
// import PropTypes from 'prop-types'
import { graphql, Link } from "gatsby"
import Img from "gatsby-image"
import Layout from "../components/layout"
// import SEO from "../components/seo"
// import Pager from "../components/pager"
import { lazy } from '#loadable/component'
import loadable from '#loadable/component'
// import Dropdown from '../components/dropdown/index'
// const Layout = loadable(() => import('../components/layout'))
const SEO = loadable(() => import('../components/seo'))
const PaginationNew = loadable(() => import('../components/page/pagination'))
const Pager = lazy(() => import('../components/pager'))
const Dropdown = lazy(() => import('../components/dropdown/index'))
export const pageQuery = graphql`
query($skip: Int!, $limit: Int!) {
site {
siteMetadata {
title
}
}
allCockpitPost(filter: {lang: {eq: "id"}, published: {value: {eq: true}}}, sort: {order: DESC, fields: date___value}, limit: $limit, skip: $skip) {
edges {
node {
id
title {
value
slug
}
image {
value {
childImageSharp {
fluid(toFormat: WEBP, webpQuality: 80, toFormatBase64: WEBP, quality: 80, pngQuality: 80, jpegQuality: 80, maxWidth: 600) {
...GatsbyImageSharpFluid_withWebp_noBase64
}
}
}
}
description {
value {
childMarkdownRemark {
excerpt(pruneLength: 160)
}
}
}
content {
value {
childMarkdownRemark {
frontmatter {
author
}
}
}
}
date {
value(formatString: " DD MMMM, YYYY")
}
}
}
}
}
`;
const PaginateTemplate = ({location, data}) =>{
return (
<Layout location={location} >
<SEO title="semua postingan" description="blog oleh pelajar dan untuk orang-orang yang ingin belajar." />
<PaginationNew data={data}/>
</Layout>
)}
export default PaginateTemplateimport React, { Suspense } from 'react'
// import PropTypes from 'prop-types'
import { graphql, Link } from "gatsby"
import Img from "gatsby-image"
import Layout from "../components/layout"
// import SEO from "../components/seo"
// import Pager from "../components/pager"
import { lazy } from '#loadable/component'
import loadable from '#loadable/component'
// import Dropdown from '../components/dropdown/index'
// const Layout = loadable(() => import('../components/layout'))
const SEO = loadable(() => import('../components/seo'))
const PaginationNew = loadable(() => import('../components/page/pagination'))
const Pager = lazy(() => import('../components/pager'))
const Dropdown = lazy(() => import('../components/dropdown/index'))
export const pageQuery = graphql`
query($skip: Int!, $limit: Int!) {
site {
siteMetadata {
title
}
}
allCockpitPost(filter: {lang: {eq: "id"}, published: {value: {eq: true}}}, sort: {order: DESC, fields: date___value}, limit: $limit, skip: $skip) {
edges {
node {
id
title {
value
slug
}
image {
value {
childImageSharp {
fluid(toFormat: WEBP, webpQuality: 80, toFormatBase64: WEBP, quality: 80, pngQuality: 80, jpegQuality: 80, maxWidth: 600) {
...GatsbyImageSharpFluid_withWebp_noBase64
}
}
}
}
description {
value {
childMarkdownRemark {
excerpt(pruneLength: 160)
}
}
}
content {
value {
childMarkdownRemark {
frontmatter {
author
}
}
}
}
date {
value(formatString: " DD MMMM, YYYY")
}
}
}
}
}
`;
const PaginateTemplate = ({location, data}) =>{
return (
<Layout location={location} >
<SEO title="semua postingan" description="blog oleh pelajar dan untuk orang-orang yang ingin belajar." />
<PaginationNew data={data}/>
</Layout>
)}
export default PaginateTemplate
I want to do that because the second code above is getting repeated by changing the tags filter in graphql, so there is a similar code like this with a different name and a different tags filter.
i also have it in gatsby-node.js for each tags..
it looked like this for kurikulum tags/ pages
const kurikulumPageResults = graphql(`
{
kurikulumPageResults: allCockpitMarkdown(filter: {childMarkdownRemark: {frontmatter: {title: {ne: ""}, tags: {eq: "kurikulum"}}}}) {
edges {
node {
childMarkdownRemark {
frontmatter {
title
slug
}
}
}
}
}
}
`).then(result => {
if (result.errors) {
Promise.reject(result.errors);
}
paginate({
createPage,
items: result.data.kurikulumPageResults.edges,
itemsPerPage: 5,
pathPrefix: '/kurikulum',
component: path.resolve('./src/templates/kurikulum.jsx'),
})
});
I found the answer by working on minimal repro.
the components look like this :
const PaginationNew = ({data}) => {
const posts = data
then adding props to the paginate template
const PaginateTemplate = ({data }) => {
const posts = data.allCockpitPost.edges
return (
<PaginationNew data={posts}/>

window is not defined - react-draft-wysiwyg used with next js (ssr)

I am working on a rich text editor used for converting plain html to editor content with next js for ssr. I got this error window is not defined so I search a solution to this github link
It used a dynamic import feature of next js.
Instead of importing the Editor directly import { Editor } from "react-draft-wysiwyg";
It uses this code to dynamically import the editor
const Editor = dynamic(
() => {
return import("react-draft-wysiwyg").then(mod => mod.Editor);
},
{ ssr: false }
);
But still I'm getting this error though I already installed this react-draft-wysiwyg module
ModuleParseError: Module parse failed: Unexpected token (19:9)
You may need an appropriate loader to handle this file type.
| import dynamic from "next/dynamic";
| var Editor = dynamic(function () {
> return import("react-draft-wysiwyg").then(function (mod) {
| return mod.Editor;
| });
And this is my whole code
import React, { Component } from "react";
import { EditorState } from "draft-js";
// import { Editor } from "react-draft-wysiwyg";
import dynamic from "next/dynamic";
const Editor = dynamic(
() => {
return import("react-draft-wysiwyg").then(mod => mod.Editor);
},
{ ssr: false }
);
class MyEditor extends Component {
constructor(props) {
super(props);
this.state = { editorState: EditorState.createEmpty() };
}
onEditorStateChange = editorState => {
this.setState({ editorState });
};
render() {
const { editorState } = this.state;
return (
<div>
<Editor
editorState={editorState}
wrapperClassName="rich-editor demo-wrapper"
editorClassName="demo-editor"
onEditorStateChange={this.onEditorStateChange}
placeholder="The message goes here..."
/>
</div>
);
}
}
export default MyEditor;
Please help me guys. Thanks.
Here is a workaround
import dynamic from 'next/dynamic'
import { EditorProps } from 'react-draft-wysiwyg'
// install #types/draft-js #types/react-draft-wysiwyg and #types/draft-js #types/react-draft-wysiwyg for types
const Editor = dynamic<EditorProps>(
() => import('react-draft-wysiwyg').then((mod) => mod.Editor),
{ ssr: false }
)
The dynamic one worked for me
import dynamic from 'next/dynamic';
const Editor = dynamic(
() => import('react-draft-wysiwyg').then((mod) => mod.Editor),
{ ssr: false }
)
import "react-draft-wysiwyg/dist/react-draft-wysiwyg.css";
const TextEditor = () => {
return (
<>
<div className="container my-5">
<Editor
toolbarClassName="toolbarClassName"
wrapperClassName="wrapperClassName"
editorClassName="editorClassName"
/>
</div>
</>
)
}
export default TextEditor
Draft.js WYSWYG with Next.js and Strapi Backend, Create and View Article with Image Upload
import React, { Component } from 'react'
import { EditorState, convertToRaw } from 'draft-js';
import draftToHtml from 'draftjs-to-html';
import dynamic from 'next/dynamic';
const Editor = dynamic(
() => import('react-draft-wysiwyg').then(mod => mod.Editor),
{ ssr: false })
import "react-draft-wysiwyg/dist/react-draft-wysiwyg.css";
export default class ArticleEditor extends Component {
constructor(props) {
super(props);
this.state = {
editorState: EditorState.createEmpty()
};
}
onEditorStateChange = (editorState) => {
this.setState({
editorState,
});
this.props.handleContent(
convertToRaw(editorState.getCurrentContent()
));
};
uploadImageCallBack = async (file) => {
const imgData = await apiClient.uploadInlineImageForArticle(file);
return Promise.resolve({ data: {
link: `${process.env.NEXT_PUBLIC_API_URL}${imgData[0].formats.small.url}`
}});
}
render() {
const { editorState } = this.state;
return (
<>
<Editor
editorState={editorState}
toolbarClassName="toolbar-class"
wrapperClassName="wrapper-class"
editorClassName="editor-class"
onEditorStateChange={this.onEditorStateChange}
toolbar={{
options: ['inline', 'blockType', 'fontSize', 'fontFamily', 'list', 'textAlign', 'colorPicker', 'link', 'embedded', 'emoji', 'image', 'history'],
inline: { inDropdown: true },
list: { inDropdown: true },
textAlign: { inDropdown: true },
link: { inDropdown: true },
history: { inDropdown: true },
image: {
urlEnabled: true,
uploadEnabled: true,
uploadCallback: this.uploadImageCallBack,
previewImage: true,
alt: { present: false, mandatory: false }
},
}}
/>
<textarea
disabled
value={draftToHtml(convertToRaw(editorState.getCurrentContent()))}
/>
</>
)
}
}
Try to return the Editor after React updates the DOM using useEffect hook. For instance:
const [editor, setEditor] = useState<boolean>(false)
useEffect(() => {
setEditor(true)
})
return (
<>
{editor ? (
<Editor
editorState={editorState}
wrapperClassName="rich-editor demo-wrapper"
editorClassName="demo-editor"
onEditorStateChange={this.onEditorStateChange}
placeholder="The message goes here..."
/>
) : null}
</>
)

Updating state based on different button clicks

I am trying to make a survey tool with firebase and react and I am implementing a template feature, so now one of the templates is working, when user clicks on create new survey, I have various buttons shown to them like: blank, temp1,temp2,temp3,temp4 based on whatever is clicked a clickhandler is triggered, now how do I update the content of the state based on which template i am getting? below is my code:
<button onClick={props.clicked} className={classes.Board}>
Board Survey
</button>
<button onClick={props.chair} className={classes.Chair}>
Chairperson Survey
</button>
<button onClick={props.member} className={classes.Member}>
Board Member Survey
</button>
And now i use
clicked={this.clickHandler}
The code to fetch survey template:
const fetchSurvey = async () => {
const res = await axios.get(
"/surveys/ckb0kmt3n000e3g5rmjnfw4go/content/questions.json"
);
return res.data;
};
Where "ckb0kmt3n000e3g5rmjnfw4go" is the survey id
const content = {
title: "Your Survey Tite",
subTitle: "Your Survey Description",
creatorDate: new Date(),
lastModified: new Date(),
questions: fetchSurvey().then(questions => {
this.setState(state => ({
...state,
content: {
...state.content,
questions
}
}));
}),
submitting: true
};
this.setState({
_id: newId(),
content: content,
userId: this.props.user_Id
});
}
Now how to do i update the questions key to run different functions based on which templates i choose on the previous page?
ClickHandler Code:
clickHandler = () => {
const newSurvey = { ...this.state };
axios
.put(
"/surveys/" + this.state._id + ".json?auth=" + this.props.token,
newSurvey
)
.then(res => {
this.props.onGetSurveyId(res.data._id);
})
.catch(error => {
console.log(error);
});
};
File1:
import React from "react";
import Button from "#material-ui/core/Button";
import Icon from "#material-ui/core/Icon";
import { makeStyles } from "#material-ui/core/styles";
import classes from "./NewSurvey.module.css";
import { Link } from "react-router-dom";
import Dialog from "#material-ui/core/Dialog";
import DialogActions from "#material-ui/core/DialogActions";
import DialogContent from "#material-ui/core/DialogContent";
import DialogTitle from "#material-ui/core/DialogTitle";
import InputLabel from "#material-ui/core/InputLabel";
import Input from "#material-ui/core/Input";
import MenuItem from "#material-ui/core/MenuItem";
import FormControl from "#material-ui/core/FormControl";
import Select from "#material-ui/core/Select";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
const NewSurvey = props => {
const [open, setOpen] = React.useState(false);
const [template, setTemplate] = React.useState("");
const handleChange = event => {
setTemplate(Number(event.target.value) || "");
};
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
const notify = () =>
toast.info("Creating Survey....Please Wait", {
position: "top-right",
autoClose: 5000,
hideProgressBar: true,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined
});
return (
<div className={classes.CreateSurvey}>
<ToastContainer
position="top-right"
autoClose={5000}
hideProgressBar
newestOnTop
closeOnClick
rtl={false}
pauseOnFocusLoss
draggable
pauseOnHover
/>
<Dialog
disableBackdropClick
disableEscapeKeyDown
open={open}
onClose={handleClose}
className={classes.Dialog}
>
<DialogTitle className={classes.DialogTitle}>
Create New Survey
</DialogTitle>
<h5 className={classes.Info}>
Choose a template or start with a blank survey
</h5>
<DialogContent>
<button
onClick={function(event) {
props.clicked();
notify();
}}
className={classes.Blank}
>
Blank Survey
</button>
<button onClick={props.board} className={classes.Board}>
Board Survey
</button>
<button onClick={props.chair} className={classes.Chair}>
Chairperson Survey
</button>
<button onClick={props.member} className={classes.Member}>
Board Member Survey
</button>
</DialogContent>
<DialogActions>
<button onClick={handleClose} className={classes.CancelButton}>
Cancel
</button>
</DialogActions>
</Dialog>
<button
className={classes.NewSurvey}
onClick={handleClickOpen}
disabled={props.isLoading || props.error}
>
<Icon className={classes.Icon}>add_circle_outline</Icon> Create New
Survey
</button>
</div>
);
};
export default NewSurvey;
File 2:
import React, { Component } from "react";
import { withRouter } from "react-router-dom";
import { connect } from "react-redux";
import newId from "../../../ulitity/idGenerator";
import axios from "../../../axios-order";
import * as actionTypes from "../../../Store/actions/actionsTypes";
import NewSurveyView from "../../../Components/NewSurvey/NewSurvey";
import { InitQuestions } from "../../../ulitity/constants/Questions";
class NewSurvey extends Component {
state = {
_id: "",
userId: "",
content: {
title: "Your Survey Title",
subTitle: "",
creatorDate: "",
lastModified: ""
}
};
componentDidMount() {
var sampleQuestion;
var questionObj;
sampleQuestion = InitQuestions["SINGLE_LINE_TEXT"]();
questionObj = {
[sampleQuestion._id]: sampleQuestion
};
var orderQuestions;
let questions = [sampleQuestion._id];
orderQuestions = questions.map(questionId => questionObj[questionId]);
const fetchBoardMember = async () => {
const res = await axios.get(
"/surveys/ckb0kmt3n000e3g5rmjnfw4go/content/questions.json"
);
return res.data;
};
const fetchBoard = async () => {
const res = await axios.get(
"/surveys/ckb24goc800013g5r7j8igrk3/content/questions.json"
);
return res.data;
};
const fetchChair = async () => {
const res = await axios.get(
"/surveys/ckb24gt3s00053g5rrf60353r/content/questions.json"
);
return res.data;
};
const content = {
title: "Your Survey Title",
subTitle: "Your Survey Description",
creatorDate: new Date(),
lastModified: new Date(),
questions: fetchBoard().then(questions => {
this.setState(state => ({
...state,
content: {
...state.content,
questions
}
}));
}),
submitting: true
};
this.setState({
_id: newId(),
content: content,
userId: this.props.user_Id
});
}
clickHandler = () => {
const newSurvey = { ...this.state };
axios
.put(
"/surveys/" + this.state._id + ".json?auth=" + this.props.token,
newSurvey
)
.then(res => {
this.props.onGetSurveyId(res.data._id);
})
.catch(error => {
console.log(error);
});
};
render() {
return (
<div>
<NewSurveyView
clicked={this.clickHandler}
board={this.boardHandler}
chair={this.chairHandler}
member={this.memberHandler}
isLoading={this.props.loading}
error={this.props.isError}
/>
</div>
);
}
}
const mapStateToProps = state => {
return {
user_Id: state.auth.userId,
token: state.auth.token,
surveyId: state.surveyEditer.survey.id
};
};
const mapDispatchToProps = dispatch => {
return {
onGetSurveyId: surveyId =>
dispatch({ type: actionTypes.GET_SURVEY_ID, surveyId: surveyId })
};
};
export default withRouter(
connect(mapStateToProps, mapDispatchToProps)(NewSurvey)
);

Categories

Resources