aboutsummaryrefslogtreecommitdiffstats
path: root/apps/Notes/components
diff options
context:
space:
mode:
authorGravatar piotrruss <mail@pruss.it> 2021-08-09 21:36:03 +0200
committerGravatar piotrruss <mail@pruss.it> 2021-08-09 21:37:03 +0200
commit464e470441287572cfda8d95484f781236b9db35 (patch)
tree87177837cb6ee6ee000f0d39fa5ba7ee6bb2943e /apps/Notes/components
downloadmy_apps-464e470441287572cfda8d95484f781236b9db35.tar.gz
my_apps-464e470441287572cfda8d95484f781236b9db35.tar.bz2
my_apps-464e470441287572cfda8d95484f781236b9db35.zip
init commit
Diffstat (limited to 'apps/Notes/components')
-rw-r--r--apps/Notes/components/List.js129
-rw-r--r--apps/Notes/components/ListItem.js119
-rw-r--r--apps/Notes/components/Note.js140
-rw-r--r--apps/Notes/components/NoteView.js63
4 files changed, 451 insertions, 0 deletions
diff --git a/apps/Notes/components/List.js b/apps/Notes/components/List.js
new file mode 100644
index 0000000..8561d4f
--- /dev/null
+++ b/apps/Notes/components/List.js
@@ -0,0 +1,129 @@
+import React, {useState, useEffect, useRef} from 'react'
+import useUser from 'lib/useUser'
+import useNotes from '../hooks/useNotes'
+import useSort from '../hooks/useSort'
+import fetchJson from 'lib/fetchJson'
+import {Layout} from 'components'
+import ListItem from './ListItem'
+import NoteView from './NoteView'
+import Note from './Note'
+
+const List = () => {
+ const [fetchedNote, setFetchedNote] = useState()
+ const [action, setAction] = useState('')
+ const {notes, error} = useNotes()
+ const [sortedBy, sortBy, sortFn] = useSort(2)
+ const {user, mutateUser} = useUser({
+ redirectToLogin: true,
+ redirectToVerify: true,
+ })
+
+ if (error) return <p>Failed to fetch notes</p>
+
+ if (!user || !user.isLoggedIn || !user.isVerified || !notes || !sortFn) {
+ return <p>Loading...</p>
+ }
+
+
+ return (
+ <>
+ {
+ action === '' && (
+ <>
+ <div className='window__submenu'>
+ <div onClick={() => setAction('addNote')}>New note</div>
+ </div>
+ <table className="list">
+ <thead>
+ <tr>
+ <th className='list__title' onClick={() => sortBy(1)}>Title {sortedBy(1)}</th>
+ <th className='list__date' onClick={() => sortBy(2)}>Created {sortedBy(2)}</th>
+ <th className='list__date' onClick={() => sortBy(3)}>Modified {sortedBy(3)}</th>
+ </tr>
+ </thead>
+ <tbody>
+ {
+ notes.length > 0
+ ? (notes.sort(sortFn).map(note => (
+ <ListItem
+ key={note._id}
+ note={note}
+ setAction={setAction}
+ setFetchedNote={setFetchedNote}
+ />
+ ))) : (
+ <tr>
+ <td>Your notes list is empty.</td>
+ </tr>
+ )}
+ </tbody>
+ </table>
+ </>
+ )
+ }
+ {
+ action === 'addNote' && (
+ <Note
+ action={action}
+ setAction={setAction}
+ />
+ )
+ }
+ {
+ action === 'showNote' && (
+ <NoteView
+ fetchedNote={fetchedNote}
+ setFetchedNote={setFetchedNote}
+ setAction={setAction}
+ />
+ )
+ }
+ {
+ action === 'editNote' && (
+ <Note
+ action={action}
+ setAction={setAction}
+ fetchedNote={fetchedNote}
+ />
+ )
+ }
+ <style jsx>{`
+ table {
+ display: block;
+ overflow: auto;
+ width: 100%;
+ table-layout: fixed;
+ word-wrap: break-word;
+ height: 100%;
+ margin-top: -1em;
+ padding-top: 1em;
+ }
+
+ tbody, thead {
+ display: block;
+ }
+
+ tr {
+ display: flex;
+ padding: 0 .5em;
+ }
+
+ th {
+ font-weight: 600;
+ text-align: left;
+ min-width: 10em;
+ white-space: nowrap;
+ padding-bottom: .5em;
+ cursor: pointer;
+ line-height: 1.1em;
+ }
+
+ th:first-of-type {
+ width: 99%;
+ }
+ `}</style>
+ </>
+ )
+}
+
+export default List
diff --git a/apps/Notes/components/ListItem.js b/apps/Notes/components/ListItem.js
new file mode 100644
index 0000000..42d67c0
--- /dev/null
+++ b/apps/Notes/components/ListItem.js
@@ -0,0 +1,119 @@
+import React, { useContext } from 'react'
+import fetchJson from 'lib/fetchJson'
+import {getNote, removeNote} from '../helpers/noteActions.js'
+import useNotes from '../hooks/useNotes'
+import Context from 'context';
+import { faEdit, faTrash } from '@fortawesome/free-solid-svg-icons'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+
+const datestring = date => {
+ const d = new Date(date);
+ return ("0" + d.getDate()).slice(-2) + "-" + ("0"+(d.getMonth()+1)).slice(-2) + "-" +
+ d.getFullYear() + " " + ("0" + d.getHours()).slice(-2) + ":" + ("0" + d.getMinutes()).slice(-2)
+};
+
+const ListItem = ({note, setAction, setFetchedNote}) => {
+ const {mutateNotes} = useNotes()
+ const {setPopup} = useContext(Context)
+
+ const handleNoteAction = async (a, note, e) => {
+ if (e) e.stopPropagation()
+ await getNote(note, setFetchedNote, setPopup, () => setAction(a))
+ }
+
+ return (
+ <>
+ <tr key={note._id}>
+ <td
+ onClick={() => handleNoteAction('showNote', note)}
+ >
+ <span>{`${note.title}`}</span>
+ <span
+ onClick={e => handleNoteAction('editNote', note, e)}
+ >
+ <FontAwesomeIcon icon={faEdit} />
+ </span>
+ <span
+ onClick={(e) => removeNote(e, note._id, mutateNotes, setPopup, setAction)}
+ >
+ <FontAwesomeIcon icon={faTrash} />
+ </span>
+ </td>
+ <td
+ onClick={() => handleNoteAction('showNote', note)}
+ >
+ {datestring(note.created_at)}
+ </td>
+ <td
+ onClick={() => handleNoteAction('showNote', note)}
+ >
+ {datestring(note.updated_at)}
+ </td>
+ </tr>
+ <style jsx>{`
+ tr {
+ display: flex;
+ padding: .5em;
+ }
+
+ td {
+ min-width: 10em;
+ white-space: nowrap;
+ }
+
+ td:first-of-type {
+ width: 99%;
+ display: flex;
+ padding-right: 1em;
+ }
+
+ td:first-of-type > span:nth-child(2),
+ td:first-of-type > span:nth-child(3) {
+ margin-left: .5em;
+ padding: .15em .5em;
+ line-height: 1em;
+ border-radius: 50%;
+ visibility: hidden;
+ opacity: 0;
+ font-size: 80%;
+ transition: .3s opacity linear .3s;
+ }
+
+ td:first-of-type > span:nth-child(1) {
+ text-overflow: ellipsis;
+ flex-grow: 1;
+ }
+
+ // td:first-of-type > span:nth-child(2) {
+ // margin-left: 1.25em;
+ // }
+
+ tr:hover {
+ background: #eee;
+ border-radius: .5em;
+ cursor: pointer;
+ }
+
+ tr:hover > td:first-of-type > span:nth-child(2),
+ tr:hover > td:first-of-type > span:nth-child(3) {
+ color: #666;
+ visibility: visible;
+ opacity: 1;
+ }
+
+ tr > td:first-of-type > span:nth-child(2):hover {
+ color: #333;
+ background-color: #deffde;
+ }
+
+ tr > td:first-of-type > span:nth-child(3):hover {
+ background-color: #ffdede;
+ color: #333;
+ }
+
+ `}</style>
+ </>
+ )
+}
+
+export default ListItem
diff --git a/apps/Notes/components/Note.js b/apps/Notes/components/Note.js
new file mode 100644
index 0000000..d23806a
--- /dev/null
+++ b/apps/Notes/components/Note.js
@@ -0,0 +1,140 @@
+import React, {useState, useContext} from 'react'
+import Context from 'context';
+import fetchJson from 'lib/fetchJson'
+import useNotes from '../hooks/useNotes'
+import {addNote, updateNote} from '../helpers/noteActions.js'
+
+const Note = ({action, setAction, fetchedNote}) => {
+ const [text, setText] = useState('')
+ const {mutateNotes} = useNotes()
+ const [errorMsg, setErrorMsg] = useState('')
+ const {setPopup} = useContext(Context)
+
+ const handleSubmit = e => {
+ e.preventDefault()
+ fetchedNote
+ ? updateNote(e, fetchedNote, mutateNotes, setAction, setPopup)
+ : addNote(e, mutateNotes, setAction, setPopup)
+ }
+
+ // if (!fetchedNote) return <p>Loading...</p>
+ // if (fetchedNote.error) {
+ // setFetchedNote()
+ // setAction('')
+ // }
+
+ return (
+ <div className='note'>
+ <h2>{fetchedNote ? 'Edit note:' : 'Add new note:'}</h2>
+ <form onSubmit={handleSubmit} className='note__form'>
+ <input
+ className='note__title'
+ name='title'
+ type='text'
+ placeholder='Title'
+ defaultValue={fetchedNote ? fetchedNote.title : ''}
+ />
+ <textarea
+ required
+ className='note__text'
+ placeholder='Note'
+ name='content'
+ defaultValue={fetchedNote ? fetchedNote.content : ''}
+ />
+ <div className='note__buttons'>
+ <span
+ className='window__button'
+ onClick={() => {setAction(fetchedNote ? 'showNote' : '')}}
+ >
+ Cancel
+ </span>
+ <input
+ className='window__button'
+ type="submit"
+ value={fetchedNote ? 'Save note' : 'Add note'}
+ />
+ </div>
+ </form>
+ <style jsx>{`
+ .note {
+ display: flex;
+ flex-direction: column;
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ background: white;
+ padding: 1em 1em 2em;
+ animation: fade-in .3s;
+ }
+
+ @keyframes fade-in {
+ from {opacity: 0;}
+ to {opacity: 1;}
+ }
+
+ h2 {
+ font-size: 1.2em;
+ margin-bottom: .5em;
+ }
+
+ .note__form {
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ flex-grow: 1;
+ }
+
+ .note__title {
+ margin-bottom: .5rem;
+ height: 3rem;
+ border: none;
+ padding: 0.5rem;
+ font-size: 1rem;
+ // font-weight: 600;
+ border: 1px dashed #666;
+ }
+
+ .note__title:placeholder {
+ font: inherit;
+ }
+
+ .note__text {
+ font-size: 1rem;
+ flex-grow: 1;
+ resize: none;
+ height: 100%;
+ width: 100%;
+ border: none;
+ border: 1px dashed #666;
+ padding: 0.5rem;
+ }
+
+ .note__text:placeholder {
+ font: inherit;
+ }
+
+ .note__close {
+ position: absolute;
+ top: 8px;
+ right: 15px;
+ transform: rotate(45deg);
+ font-size: 26px;
+ cursor: pointer;
+ transition: .3s transform;
+ }
+
+ .note__close:hover {
+ transform: rotate(135deg);
+ }
+
+ .note__buttons {
+ text-align: right;
+ }
+ `}</style>
+ </div>
+ )
+}
+
+export default Note
diff --git a/apps/Notes/components/NoteView.js b/apps/Notes/components/NoteView.js
new file mode 100644
index 0000000..15d4944
--- /dev/null
+++ b/apps/Notes/components/NoteView.js
@@ -0,0 +1,63 @@
+import React, {useContext} from 'react';
+import Context from 'context';
+import useNotes from '../hooks/useNotes'
+import {removeNote} from '../helpers/noteActions.js'
+
+const NoteView = ({fetchedNote, setFetchedNote, setAction}) => {
+ const {mutateNotes} = useNotes()
+ const {setPopup} = useContext(Context)
+
+ if (!fetchedNote) return <p>Loading...</p>
+ if (fetchedNote.error) {
+ setFetchedNote()
+ setAction('')
+ }
+
+ const {_id, content, title} = fetchedNote
+
+ return (
+ <section>
+ <div className='window__submenu'>
+ <div onClick={() => { setFetchedNote(); setAction('') }}>Back</div>
+ <div>Copy</div>
+ <div onClick={() => { setAction('editNote')}}>Edit</div>
+ <div onClick={e => { removeNote(e, _id, mutateNotes, setPopup, setAction) }}>Remove</div>
+ </div>
+
+ <div className='window__scroll'>
+ <h2 className='selectable'>{title}</h2>
+ <p className='selectable'>{content}</p>
+ </div>
+ <style jsx>{`
+ section {
+ background: white;
+ padding: 1rem;
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ animation: fade-in .3s;
+ }
+
+ @keyframes fade-in {
+ from {opacity: 0;}
+ to {opacity: 1;}
+ }
+
+ h2 {
+ font-size: 1.25em;
+ font-weight: 600;
+ padding: 1rem;
+ }
+
+ p {
+ padding: 0 1rem 1rem;
+ white-space: pre-line;
+ }
+ `}</style>
+ </section>
+ )
+}
+
+export default NoteView