Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions src/components/NoteManager/components/NotesActions.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import "./NotesActions.css";
import { type ChangeEventHandler, useCallback, useContext, useRef, useState } from "react";
import Modal from "react-modal";
import { Tooltip } from "react-tooltip";
import { type INotesContext, NotesContext } from "../../NotesProvider/NotesProvider";
import { RemoteSources } from "../../RemoteSources/RemoteSources";

Expand All @@ -26,10 +27,13 @@ export function NotesActions() {
handleRedo,
handleImport,
handleExport,
handleDeleteNotes,
handleSetRemoteSources,
} = useContext(NotesContext) as INotesContext;

const [isModalOpen, setModalOpen] = useState(false);
const [confirmDelete, setConfirmDelete] = useState(false);
const [confirmDeleteDisabled, setConfirmDeleteDisabled] = useState(false);

const fileImport = useRef<HTMLInputElement>(null);
const onImport = useCallback(() => {
Expand Down Expand Up @@ -62,6 +66,19 @@ export function NotesActions() {
setModalOpen((x) => !x);
}, []);

const deleteNotes = useCallback(() => {
if (confirmDeleteDisabled) return;
if (confirmDelete) {
handleDeleteNotes();
setConfirmDelete(false);
} else {
setConfirmDelete(true);
setConfirmDeleteDisabled(true);
window.setTimeout(() => setConfirmDelete(false), 10000);
window.setTimeout(() => setConfirmDeleteDisabled(false), 3000);
}
}, [confirmDelete, confirmDeleteDisabled, handleDeleteNotes]);

return (
<>
<div className="notes-actions">
Expand All @@ -73,8 +90,18 @@ export function NotesActions() {
</button>
<button onClick={onImport}>📂 import</button>
<button onClick={handleExport}>💾 export</button>
<button
data-tooltip-id="delete-tooltip"
data-tooltip-content={confirmDelete ? "Yes, delete" : "Delete all notes"}
data-tooltip-place="bottom"
disabled={confirmDeleteDisabled}
onClick={deleteNotes}
>
{confirmDelete ? "Are you sure?" : "🗑 delete"}
</button>
<button onClick={toggleModal}>⚙︎</button>
</div>
<Tooltip id="delete-tooltip" />
<input ref={fileImport} onChange={handleFileSelected} type="file" style={{ display: "none" }} />
<Modal style={modalStyles} isOpen={isModalOpen} onRequestClose={toggleModal} contentLabel="Settings">
<button className="settings-close" onClick={toggleModal}>
Expand Down
40 changes: 39 additions & 1 deletion src/components/NotesProvider/NotesProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { type ReactNode, createContext, useCallback, useContext, useEffect, useMemo, useState } from "react";
import { type ILocationContext, LocationContext } from "../LocationProvider/LocationProvider";
import { LABEL_IMPORTED } from "./consts/labels";
import { LABEL_IMPORTED, LABEL_LOCAL, LABEL_REMOTE } from "./consts/labels";
import { NEW_REMOTE_SOURCE_ID } from "./consts/remoteSources";
import { useDecoratedNotes } from "./hooks/useDecoratedNotes";
import { type ILabel, useLabels } from "./hooks/useLabels";
Expand Down Expand Up @@ -33,6 +33,7 @@ export interface INotesContext {
handleRedo(): void;
handleImport(jsonStr: string, label: string): void;
handleExport(): void;
handleDeleteNotes(): void;
handleToggleLabel(label: string): void;
}

Expand Down Expand Up @@ -75,6 +76,23 @@ export function NotesProvider({ children }: INotesProviderProps) {
notes.saveToLocalStorage(newNotes);
}, []);

// Filter notes by labels.
const filterNotesByLabels = useCallback(
(
notes: IStorageNote[],
labels: string[],
{ includesLabel }: { includesLabel: boolean } = { includesLabel: true },
): IStorageNote[] => {
return notes.filter((note) => {
if (note.labels.some((label) => labels.includes(label))) {
return includesLabel;
}
return !includesLabel;
});
},
[],
);

// Decorate all local notes.
useEffect(() => {
setLocalNotesReady(false);
Expand Down Expand Up @@ -206,6 +224,26 @@ export function NotesProvider({ children }: INotesProviderProps) {
const fileName = `graypaper-notes-${new Date().toISOString()}.json`;
downloadNotesAsJson(localNotes, fileName);
}, [localNotes]),
handleDeleteNotes: useCallback(() => {
const activeLabels = labels
.filter((label) => label.isActive)
.map((label) => {
const parts = label.label.split("/");
if (parts.length > 1) {
if (parts[0] === LABEL_LOCAL || parts[0] === LABEL_REMOTE) {
return parts.slice(1).join("/");
}
}
return label.label;
});

const fileName = `removed-graypaper-notes-${new Date().toISOString()}.json`;
const deletedNotes = filterNotesByLabels(localNotes.notes, activeLabels);
downloadNotesAsJson({ version: 3, notes: deletedNotes }, fileName);

const updatedNotes = filterNotesByLabels(localNotes.notes, activeLabels, { includesLabel: false });
updateLocalNotes(localNotes, { ...localNotes, notes: updatedNotes });
}, [localNotes, labels, updateLocalNotes, filterNotesByLabels]),
};

return <NotesContext.Provider value={context}>{children}</NotesContext.Provider>;
Expand Down