/* Copyright (C) 2019, 2020 Monomax Software Pty Ltd * * This file is part of Dnote. * * Dnote is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Dnote is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Dnote. If not, see . */ import React, { useState, useEffect, useCallback } from 'react'; import classnames from 'classnames'; import { KEYCODE_ENTER } from 'jslib/helpers/keyboard'; import initServices from '../utils/services'; import BookSelector from './BookSelector'; import Flash from './Flash'; import { useSelector, useDispatch } from '../store/hooks'; import { updateContent, resetComposer } from '../store/composer/actions'; import { fetchBooks } from '../store/books/actions'; import { navigate } from '../store/location/actions'; interface Props {} // focusBookSelectorInput focuses on the input element of the book selector. // It needs to traverse the tree returned by the ref API of the 'react-select' library, // and to guard against possible breaking changes, if the path does not exist, it noops. function focusBookSelectorInput(bookSelectorRef) { return ( bookSelectorRef.select && bookSelectorRef.select.select && bookSelectorRef.select.select.inputRef && bookSelectorRef.select.select.inputRef.focus() ); } function useFetchData() { const dispatch = useDispatch(); const { books } = useSelector(state => ({ books: state.books })); useEffect(() => { if (!books.isFetched) { dispatch(fetchBooks()); } }, [dispatch, books.isFetched]); } function useInitFocus(contentRef, bookSelectorRef) { const { composer, books } = useSelector(state => ({ composer: state.composer, books: state.books })); useEffect(() => { if (!books.isFetched) { return () => null; } if (bookSelectorRef && contentRef) { if (composer.bookLabel === '') { focusBookSelectorInput(bookSelectorRef); } else { contentRef.focus(); } } return () => null; }, [contentRef, bookSelectorRef, books.isFetched, composer.bookLabel]); } const Composer: React.FunctionComponent = () => { useFetchData(); const [contentFocused, setContentFocused] = useState(false); const [submitting, setSubmitting] = useState(false); const [errMsg, setErrMsg] = useState(''); const dispatch = useDispatch(); const [contentRef, setContentEl] = useState(null); const [bookSelectorRef, setBookSelectorEl] = useState(null); const { composer, settings, auth } = useSelector(state => ({ composer: state.composer, settings: state.settings, auth: state.auth })); const handleSubmit = useCallback( async e => { e.preventDefault(); const services = initServices(settings.apiUrl); setSubmitting(true); try { let bookUUID; if (composer.bookUUID === '') { const resp = await services.books.create( { name: composer.bookLabel }, { headers: { Authorization: `Bearer ${auth.sessionKey}` } } ); bookUUID = resp.book.uuid; } else { bookUUID = composer.bookUUID; } const resp = await services.notes.create( { book_uuid: bookUUID, content: composer.content }, { headers: { Authorization: `Bearer ${auth.sessionKey}` } } ); // clear the composer state setErrMsg(''); setSubmitting(false); dispatch(resetComposer()); // navigate dispatch( navigate('/success', { bookName: composer.bookLabel, noteUUID: resp.result.uuid }) ); } catch (err) { setErrMsg(err.message); setSubmitting(false); } }, [ settings.apiUrl, composer.bookUUID, composer.content, composer.bookLabel, auth.sessionKey, dispatch ] ); useEffect(() => { const handleSubmitShortcut = e => { // Shift + Enter if (e.shiftKey && e.keyCode === KEYCODE_ENTER) { handleSubmit(e); } }; window.addEventListener('keydown', handleSubmitShortcut); return () => { window.removeEventListener('keydown', handleSubmitShortcut); }; }, [composer, handleSubmit]); let submitBtnText: string; if (submitting) { submitBtnText = 'Saving...'; } else { submitBtnText = 'Save'; } useInitFocus(contentRef, bookSelectorRef); return (
{ contentRef.focus(); }} />