import React, { createRef } from 'react'; import { Keyboard, StyleSheet, TextInput, TouchableOpacity, View } from 'react-native'; import { FlatList } from 'react-native-gesture-handler'; import { notesnook } from '../../../e2e/test.ids'; import { useMenuStore } from '../../provider/stores'; import { DDS } from '../../services/DeviceDetection'; import { eSubscribeEvent, eUnSubscribeEvent, ToastEvent } from '../../services/EventManager'; import Navigation from '../../services/Navigation'; import { db } from '../../utils/database'; import { eCloseAddNotebookDialog, eOpenAddNotebookDialog } from '../../utils/events'; import { ph, pv, SIZE } from '../../utils/size'; import { sleep } from '../../utils/time'; import { IconButton } from '../ui/icon-button'; import { Button } from '../ui/button'; import DialogHeader from '../dialog/dialog-header'; import Input from '../ui/input'; import { MoveNotes } from '../MoveNoteDialog/movenote'; import Seperator from '../ui/seperator'; import SheetWrapper from '../ui/sheet'; import { Toast } from '../toast'; let refs = []; export class AddNotebookDialog extends React.Component { constructor(props) { super(props); this.state = { notebook: null, visible: false, topics: [], description: null, titleFocused: false, descFocused: false, count: 0, topicInputFocused: false, editTopic: false, loading: false }; this.title = null; this.description = null; this.listRef; this.prevItem = null; this.prevIndex = null; this.currentSelectedInput = null; this.id = null; this.backPressCount = 0; this.currentInputValue = null; this.titleRef; this.descriptionRef; this.topicsToDelete = []; this.hiddenInput = createRef(); this.topicInputRef = createRef(); this.addingTopic = false; this.actionSheetRef = createRef(); } componentDidMount() { eSubscribeEvent(eOpenAddNotebookDialog, this.open); eSubscribeEvent(eCloseAddNotebookDialog, this.close); } componentWillUnmount() { eUnSubscribeEvent(eOpenAddNotebookDialog, this.open); eUnSubscribeEvent(eCloseAddNotebookDialog, this.close); } open = notebook => { refs = []; if (notebook) { let topicsList = []; notebook.topics.forEach((item, index) => { topicsList.push(item.title); }); this.id = notebook.id; this.title = notebook.title; this.description = notebook.description; this.setState({ topics: [...topicsList], visible: true, notebook: notebook }); } else { this.setState({ visible: true, notebook: null }); } sleep(100).then(r => { this.actionSheetRef.current?.show(); }); }; close = () => { this.actionSheetRef.current?.hide(); refs = []; this.prevIndex = null; this.prevItem = null; this.currentSelectedInput = null; this.title = null; this.description = null; this.currentInputValue = null; this.id = null; }; onDelete = index => { let { topics } = this.state; let prevTopics = topics; refs = []; prevTopics.splice(index, 1); let edit = this.state.notebook; if (edit && edit.id) { let topicToDelete = edit.topics[index]; if (topicToDelete) { this.topicsToDelete.push(topicToDelete.id); } } let nextTopics = [...prevTopics]; if (this.prevIndex === index) { this.prevIndex = null; this.prevItem = null; this.currentInputValue = null; this.topicInputRef.current?.setNativeProps({ text: null }); } this.setState({ topics: nextTopics }); }; addNewNotebook = async () => { this.setState({ loading: true }); let { topics, notebook } = this.state; if (!this.title || this.title?.trim().length === 0) { ToastEvent.show({ heading: 'Notebook title is required', type: 'error', context: 'local' }); this.setState({ loading: false }); return; } let toEdit = null; if (notebook) { toEdit = db.notebooks.notebook(notebook.id).data; } let prevTopics = [...topics]; if (this.currentInputValue && this.currentInputValue.trim().length !== 0) { if (this.prevItem != null) { prevTopics[this.prevIndex] = this.currentInputValue; } else { prevTopics.push(this.currentInputValue); this.currentInputValue = null; } } let newNotebookId = null; if (notebook) { if (this.topicsToDelete?.length > 0) { await db.notebooks.notebook(toEdit.id).topics.delete(...this.topicsToDelete); toEdit = db.notebooks.notebook(toEdit.id).data; } await db.notebooks.add({ title: this.title, description: this.description, id: notebook.id }); let nextTopics = toEdit.topics.map((topic, index) => { let copy = { ...topic }; copy.title = prevTopics[index]; return copy; }); prevTopics.forEach((title, index) => { if (!nextTopics[index]) { nextTopics.push(title); } }); await db.notebooks.notebook(toEdit.id).topics.add(...nextTopics); } else { newNotebookId = await db.notebooks.add({ title: this.title, description: this.description, topics: prevTopics, id: null }); } useMenuStore.getState().setMenuPins(); Navigation.setRoutesToUpdate([ Navigation.routeNames.Notebooks, Navigation.routeNames.Notebook, Navigation.routeNames.NotesPage ]); this.setState({ loading: false }); this.close(); await sleep(300); if (!notebook) { MoveNotes.present(db.notebooks.notebook(newNotebookId).data); } }; onSubmit = (forward = true) => { this.hiddenInput.current?.focus(); let willFocus = true; let { topics } = this.state; if (!this.currentInputValue || this.currentInputValue?.trim().length === 0) return; let prevTopics = [...topics]; if (this.prevItem === null) { prevTopics.push(this.currentInputValue); this.setState({ topics: prevTopics }); setTimeout(() => { this.listRef.scrollToEnd({ animated: true }); }, 30); this.currentInputValue = null; } else { prevTopics[this.prevIndex] = this.currentInputValue; this.setState({ topics: prevTopics }); this.currentInputValue = null; if (this.state.editTopic) { this.topicInputRef.current?.blur(); Keyboard.dismiss(); this.setState({ editTopic: false }); willFocus = false; } this.prevItem = null; this.prevIndex = null; this.currentInputValue = null; if (forward) { setTimeout(() => { this.listRef.scrollToEnd({ animated: true }); }, 30); } } this.topicInputRef.current?.setNativeProps({ text: '' }); willFocus && this.topicInputRef.current?.focus(); }; render() { const { colors } = this.props; const { topics, visible, topicInputFocused, notebook } = this.state; if (!visible) return null; return ( { this.topicsToDelete = []; await sleep(300); !this.state.notebook && this.titleRef?.focus(); }} fwdRef={this.actionSheetRef} onClose={() => { this.close(); this.setState({ visible: false, topics: [], descFocused: false, titleFocused: false, editTopic: false, notebook: null }); }} statusBarTranslucent={false} onRequestClose={this.close} > (this.titleRef = ref)} testID={notesnook.ids.dialogs.notebook.inputs.title} onChangeText={value => { this.title = value; }} placeholder="Enter a title" onSubmit={() => { this.descriptionRef.focus(); }} returnKeyLabel="Next" returnKeyType="next" defaultValue={notebook ? notebook.title : null} /> (this.descriptionRef = ref)} testID={notesnook.ids.dialogs.notebook.inputs.description} onChangeText={value => { this.description = value; }} placeholder="Describe your notebook." onSubmit={() => { this.topicInputRef.current?.focus(); }} returnKeyLabel="Next" returnKeyType="next" defaultValue={notebook ? notebook.description : null} /> { this.currentInputValue = value; if (this.prevItem !== null) { refs[this.prevIndex].setNativeProps({ text: value, style: { borderBottomColor: colors.accent } }); } }} returnKeyLabel="Done" returnKeyType="done" onSubmit={() => { this.onSubmit(); }} blurOnSubmit={false} button={{ icon: this.state.editTopic ? 'check' : 'plus', onPress: this.onSubmit, color: topicInputFocused ? colors.accent : colors.icon }} placeholder="Add a topic" /> (this.listRef = ref)} nestedScrollEnabled keyExtractor={(item, index) => item + index.toString()} onMomentumScrollEnd={() => { this.actionSheetRef.current?.handleChildScrollEnd(); }} keyboardShouldPersistTaps="always" keyboardDismissMode="interactive" ListFooterComponent={} renderItem={({ item, index }) => ( { this.prevIndex = index; this.prevItem = item; this.topicInputRef.current?.setNativeProps({ text: item }); this.topicInputRef.current?.focus(); this.currentInputValue = item; this.setState({ editTopic: true }); }} onDelete={this.onDelete} index={index} colors={colors} /> )} />