/* This file is part of the Notesnook project (https://notesnook.com/) Copyright (C) 2023 Streetwriters (Private) Limited This program 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. This program 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 this program. If not, see . */ import { ContentBlock, Note, VirtualizedGrouping, createInternalLink } from "@notesnook/core"; import type { LinkAttributes } from "@notesnook/editor"; import { NativeEvents } from "@notesnook/editor-mobile/src/utils/native-events"; import { strings } from "@notesnook/intl"; import { useThemeColors } from "@notesnook/theme"; import React, { useEffect, useRef, useState } from "react"; import { TextInput, View } from "react-native"; import { FlatList } from "react-native-actions-sheet"; import { db } from "../../../common/database"; import { useDBItem } from "../../../hooks/use-db-item"; import { editorController } from "../../../screens/editor/tiptap/utils"; import { presentSheet } from "../../../services/event-manager"; import { defaultBorderRadius, AppFontSize } from "../../../utils/size"; import { Button } from "../../ui/button"; import Input from "../../ui/input"; import { Pressable } from "../../ui/pressable"; import Paragraph from "../../ui/typography/paragraph"; const ListNoteItem = ({ id, items, onSelectNote }: { id: any; items: VirtualizedGrouping | undefined; onSelectNote: any; }) => { const [item] = useDBItem(id, "note", items); return ( { if (!item) return; onSelectNote(item as Note); }} type={"transparent"} style={{ paddingVertical: 12, flexDirection: "row", width: "100%", justifyContent: "flex-start", height: 50 }} > {item?.title} ); }; const ListBlockItem = ({ item, onSelectBlock }: { item: ContentBlock; onSelectBlock: any; }) => { const { colors } = useThemeColors(); return ( { onSelectBlock(item); }} type={"transparent"} style={{ flexDirection: "row", width: "100%", justifyContent: "flex-start", minHeight: 45 }} > {item?.content.length > 200 ? item?.content.slice(0, 200) + "..." : !item.content || item.content.trim() === "" ? strings.linkNoteEmptyBlock() : item.content} {item.type.toUpperCase()} ); }; export default function LinkNote(props: { attributes: LinkAttributes; resolverId: string; onLinkCreated: () => void; close?: (ctx?: string) => void; }) { const { colors } = useThemeColors(); const query = useRef(); const [notes, setNotes] = useState>(); const nodesRef = useRef([]); const [nodes, setNodes] = useState([]); const inputRef = useRef(); const [selectedNote, setSelectedNote] = useState(); const [selectedNodeId, setSelectedNodeId] = useState(); useEffect(() => { db.notes.all.sorted(db.settings.getGroupOptions("notes")).then((notes) => { setNotes(notes); }); }, []); const onChange = async (value: string) => { query.current = value; if (!selectedNote) { const notes = await db.lookup.notes(value).sorted(); setNotes(notes); } else { if (value.startsWith("#")) { const headingNodes = nodesRef.current.filter((n) => n.type.match(/(h1|h2|h3|h4|h5|h6)/g) ); setNodes( headingNodes.filter((n) => n.content.includes(value.slice(1))) ); } else { setNodes(nodesRef.current.filter((n) => n.content.includes(value))); } } }; const onCreateLink = (blockId?: string) => { if (!selectedNote) return; const link = createInternalLink( "note", selectedNote.id, blockId ? { blockId: blockId } : undefined ); editorController.current?.postMessage(NativeEvents.resolve, { data: { href: link, title: selectedNote.title }, resolverId: props.resolverId }); }; const onSelectNote = async (note: Note) => { setSelectedNote(note); inputRef.current?.clear(); setTimeout(async () => { nodesRef.current = await db.notes.contentBlocks(note.id); setNodes(nodesRef.current); }); // Fetch and set note's nodes. }; const onSelectBlock = (block: ContentBlock) => { onCreateLink(block.id); props.onLinkCreated(); props.close?.(); }; return ( { onChange(value); }} /> {selectedNote ? ( {strings.linkNoteSelectedNote()} { setSelectedNote(undefined); setSelectedNodeId(undefined); setNodes([]); }} style={{ flexDirection: "row", width: "100%", justifyContent: "flex-start", height: 45, borderWidth: 1, borderColor: colors.primary.accent, paddingHorizontal: 12 }} type="secondaryAccented" > {selectedNote?.title} {strings.tapToDeselect()} {nodes?.length > 0 ? ( {strings.linkNoteToSection()} ) : null} ) : null} {selectedNote ? ( ( )} style={{ marginTop: 10 }} keyboardShouldPersistTaps="handled" windowSize={3} keyExtractor={(item) => item.id} data={nodes} /> ) : ( ( )} keyboardShouldPersistTaps="handled" style={{ marginTop: 10 }} windowSize={3} data={notes?.placeholders} /> )} {selectedNote ? (