From f7614302a354c3944ca536aef1777de7306e931b Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 22 Sep 2021 12:24:11 +0200 Subject: [PATCH] Create snippet form and functionality --- client/src/App.tsx | 18 ++- client/src/components/Navigation/routes.json | 4 + .../src/components/Snippets/SnippetForm.tsx | 129 ++++++++++++++++++ client/src/components/UI/Button.tsx | 6 +- client/src/components/UI/Layout.tsx | 2 +- client/src/components/UI/index.ts | 1 - client/src/containers/Editor.tsx | 32 +++++ client/src/containers/index.ts | 4 + client/src/index.tsx | 5 +- client/src/store/SnippetsContext.tsx | 46 ++++++- client/src/typescript/interfaces/Context.ts | 6 +- 11 files changed, 236 insertions(+), 17 deletions(-) create mode 100644 client/src/components/Snippets/SnippetForm.tsx create mode 100644 client/src/containers/Editor.tsx create mode 100644 client/src/containers/index.ts diff --git a/client/src/App.tsx b/client/src/App.tsx index 2f34191..c579af9 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,16 +1,20 @@ import { BrowserRouter, Switch, Route } from 'react-router-dom'; import { Navbar } from './components/Navigation/Navbar'; -import { Home, Snippet, Snippets } from './containers'; +import { Editor, Home, Snippet, Snippets } from './containers'; +import { SnippetsContextProvider } from './store'; export const App = () => { return ( - - - - - - + + + + + + + + + ); }; diff --git a/client/src/components/Navigation/routes.json b/client/src/components/Navigation/routes.json index 534635f..b2db906 100644 --- a/client/src/components/Navigation/routes.json +++ b/client/src/components/Navigation/routes.json @@ -7,6 +7,10 @@ { "name": "Snippets", "dest": "/snippets" + }, + { + "name": "Editor", + "dest": "/editor" } ] } diff --git a/client/src/components/Snippets/SnippetForm.tsx b/client/src/components/Snippets/SnippetForm.tsx new file mode 100644 index 0000000..9724fde --- /dev/null +++ b/client/src/components/Snippets/SnippetForm.tsx @@ -0,0 +1,129 @@ +import { ChangeEvent, FormEvent, Fragment, useState, useContext } from 'react'; +import { SnippetsContext } from '../../store'; +import { NewSnippet } from '../../typescript/interfaces'; +import { Button, Card } from '../UI'; + +export const SnippetForm = (): JSX.Element => { + const { createSnippet } = useContext(SnippetsContext); + + const [formData, setFormData] = useState({ + title: '', + description: '', + language: '', + code: '', + docs: '' + }); + + const inputHandler = ( + e: ChangeEvent + ) => { + setFormData({ + ...formData, + [e.target.name]: e.target.value + }); + }; + + const formHandler = (e: FormEvent) => { + e.preventDefault(); + createSnippet(formData); + }; + + return ( + +
+ +
formHandler(e)}> + {/* DETAILS SECTION */} +
Snippet details
+ + {/* TITLE */} +
+ + inputHandler(e)} + /> +
+ + {/* DESCRIPTION */} +
+ + inputHandler(e)} + /> +
+ + {/* LANGUAGE */} +
+ + inputHandler(e)} + /> +
+
+ + {/* CODE SECTION */} +
Snippet code
+
+ +
+
+ + {/* DOCS SECTION */} +
Snippet documentation
+
+ +
+ + {/* SUBMIT SECTION */} +
+
+
+
+
+
+ ); +}; diff --git a/client/src/components/UI/Button.tsx b/client/src/components/UI/Button.tsx index 8462bf1..5a492f9 100644 --- a/client/src/components/UI/Button.tsx +++ b/client/src/components/UI/Button.tsx @@ -7,6 +7,7 @@ interface Props { small?: boolean; handler?: () => void; classes?: string; + type?: 'button' | 'submit' | 'reset'; } export const Button = (props: Props): JSX.Element => { @@ -16,7 +17,8 @@ export const Button = (props: Props): JSX.Element => { outline = false, small = false, handler, - classes = '' + classes = '', + type = 'button' } = props; const elClasses = [ @@ -27,7 +29,7 @@ export const Button = (props: Props): JSX.Element => { ]; return ( - ); diff --git a/client/src/components/UI/Layout.tsx b/client/src/components/UI/Layout.tsx index 5efc6df..71a7ffa 100644 --- a/client/src/components/UI/Layout.tsx +++ b/client/src/components/UI/Layout.tsx @@ -4,7 +4,7 @@ interface Props { export const Layout = (props: Props): JSX.Element => { return ( -
+
{props.children}
); diff --git a/client/src/components/UI/index.ts b/client/src/components/UI/index.ts index ad2a72f..b0fe2eb 100644 --- a/client/src/components/UI/index.ts +++ b/client/src/components/UI/index.ts @@ -4,4 +4,3 @@ export * from './Card'; export * from './PageHeader'; export * from './Spinner'; export * from './Button'; -export * from './List'; diff --git a/client/src/containers/Editor.tsx b/client/src/containers/Editor.tsx new file mode 100644 index 0000000..1ba8df5 --- /dev/null +++ b/client/src/containers/Editor.tsx @@ -0,0 +1,32 @@ +import { Fragment } from 'react'; +import { useLocation } from 'react-router-dom'; +import { SnippetForm } from '../components/Snippets/SnippetForm'; +import { Layout, PageHeader } from '../components/UI'; +import { Snippet } from '../typescript/interfaces'; + +interface Props { + snippet?: Snippet; +} + +export const Editor = (props: Props): JSX.Element => { + const { snippet } = props; + + // Get previous location + const location = useLocation<{ from: string }>(); + const { from } = location.state || '/snippets'; + + return ( + + {snippet ? ( + + + + ) : ( + + + + + )} + + ); +}; diff --git a/client/src/containers/index.ts b/client/src/containers/index.ts new file mode 100644 index 0000000..71b0f1d --- /dev/null +++ b/client/src/containers/index.ts @@ -0,0 +1,4 @@ +export * from './Home'; +export * from './Snippet'; +export * from './Snippets'; +export * from './Editor'; diff --git a/client/src/index.tsx b/client/src/index.tsx index 518e3bf..6fa65f4 100644 --- a/client/src/index.tsx +++ b/client/src/index.tsx @@ -2,13 +2,10 @@ import React from 'react'; import ReactDOM from 'react-dom'; import './bootstrap.min.css'; import { App } from './App'; -import { SnippetsContextProvider } from './store'; ReactDOM.render( - - - + , document.getElementById('root') ); diff --git a/client/src/store/SnippetsContext.tsx b/client/src/store/SnippetsContext.tsx index 89fe565..a9bf989 100644 --- a/client/src/store/SnippetsContext.tsx +++ b/client/src/store/SnippetsContext.tsx @@ -1,16 +1,22 @@ import { useState, createContext } from 'react'; +import { useHistory } from 'react-router-dom'; import axios from 'axios'; import { Context, Snippet, Response, - LanguageCount + LanguageCount, + NewSnippet } from '../typescript/interfaces'; export const SnippetsContext = createContext({ snippets: [], + currentSnippet: null, languageCount: [], getSnippets: () => {}, + getSnippetById: (id: number) => {}, + setSnippet: (id: number) => {}, + createSnippet: (snippet: NewSnippet) => {}, countSnippets: () => {} }); @@ -20,8 +26,11 @@ interface Props { export const SnippetsContextProvider = (props: Props): JSX.Element => { const [snippets, setSnippets] = useState([]); + const [currentSnippet, setCurrentSnippet] = useState(null); const [languageCount, setLanguageCount] = useState([]); + const history = useHistory(); + const getSnippets = (): void => { axios .get>('/api/snippets') @@ -29,6 +38,37 @@ export const SnippetsContextProvider = (props: Props): JSX.Element => { .catch(err => console.log(err)); }; + const getSnippetById = (id: number): void => { + axios + .get>(`/api/snippets/${id}`) + .then(res => setCurrentSnippet(res.data.data)) + .catch(err => console.log(err)); + }; + + const setSnippet = (id: number): void => { + if (id < 0) { + setCurrentSnippet(null); + return; + } + + const snippet = snippets.find(s => s.id === id); + + if (snippet) { + setCurrentSnippet(snippet); + } + }; + + const createSnippet = (snippet: NewSnippet): void => { + axios + .post>('/api/snippets', snippet) + .then(res => { + setSnippets([...snippets, res.data.data]); + setCurrentSnippet(res.data.data); + history.push(`/snippet/${res.data.data.id}`); + }) + .catch(err => console.log(err)); + }; + const countSnippets = (): void => { axios .get>('/api/snippets/statistics/count') @@ -38,8 +78,12 @@ export const SnippetsContextProvider = (props: Props): JSX.Element => { const context = { snippets, + currentSnippet, languageCount, getSnippets, + getSnippetById, + setSnippet, + createSnippet, countSnippets }; diff --git a/client/src/typescript/interfaces/Context.ts b/client/src/typescript/interfaces/Context.ts index 16bae40..bd99dc1 100644 --- a/client/src/typescript/interfaces/Context.ts +++ b/client/src/typescript/interfaces/Context.ts @@ -1,8 +1,12 @@ -import { LanguageCount, Snippet } from '.'; +import { LanguageCount, NewSnippet, Snippet } from '.'; export interface Context { snippets: Snippet[]; + currentSnippet: Snippet | null; languageCount: LanguageCount[]; getSnippets: () => void; + getSnippetById: (id: number) => void; + setSnippet: (id: number) => void; + createSnippet: (snippet: NewSnippet) => void; countSnippets: () => void; }