diff --git a/apps/web/src/components/checkbox/index.js b/apps/web/src/components/checkbox/index.js
index 937b16a15..6ffcfc4fd 100644
--- a/apps/web/src/components/checkbox/index.js
+++ b/apps/web/src/components/checkbox/index.js
@@ -10,9 +10,12 @@ const CheckBox = props => {
return (
{
- setChecked(!checked);
if (props.onChecked) {
props.onChecked(!checked);
+ setChecked(!checked);
+ }
+ if (props.onClick) {
+ props.onClick();
}
}}
width="full"
diff --git a/apps/web/src/components/dialogs/password-dialog.js b/apps/web/src/components/dialogs/password-dialog.js
new file mode 100644
index 000000000..26755a4f4
--- /dev/null
+++ b/apps/web/src/components/dialogs/password-dialog.js
@@ -0,0 +1,96 @@
+import React, { useState, useRef, useCallback } from "react";
+import { Box, Text, Flex } from "rebass";
+import { Input } from "@rebass/forms";
+import Dialog, { showDialog } from "./dialog";
+import * as Icon from "react-feather";
+
+function PasswordDialog(props) {
+ const [isWrong, setIsWrong] = useState(false);
+ const passwordRef = useRef();
+ const submit = useCallback(async () => {
+ const password = passwordRef.current.value;
+ if (await props.validate(password)) {
+ props.onDone();
+ } else {
+ setIsWrong(true);
+ passwordRef.current.focus();
+ }
+ }, [setIsWrong, props]);
+ return (
+
}
- pinned={note.pinned}
+ pinned={props.pinnable && note.pinned}
menuData={note}
menuItems={menuItems(note, index)}
dropdownRefs={dropdownRefs}
@@ -104,6 +125,7 @@ export default React.memo(Note, function(prevProps, nextProps) {
prevItem.pinned === nextItem.pinned &&
prevItem.favorite === nextItem.favorite &&
prevItem.headline === nextItem.headline &&
- prevItem.title === nextItem.title
+ prevItem.title === nextItem.title &&
+ prevItem.locked === nextItem.locked
);
});
diff --git a/apps/web/src/components/properties/index.js b/apps/web/src/components/properties/index.js
index c26ace710..e3da2ab72 100644
--- a/apps/web/src/components/properties/index.js
+++ b/apps/web/src/components/properties/index.js
@@ -12,12 +12,14 @@ import { motion } from "framer-motion";
const Properties = props => {
const pinned = useStore(store => store.session.pinned);
const favorite = useStore(store => store.session.favorite);
+ const locked = useStore(store => store.session.locked);
const colors = useStore(store => store.session.colors);
const tags = useStore(store => store.session.tags);
const setSession = useStore(store => store.setSession);
const setColor = useStore(store => store.setColor);
const setTag = useStore(store => store.setTag);
+ const toggleLocked = useStore(store => store.toggleLocked);
const hideProperties = useAppStore(store => store.hideProperties);
const showProperties = useAppStore(store => store.showProperties);
const arePropertiesVisible = useAppStore(store => store.arePropertiesVisible);
@@ -118,7 +120,8 @@ const Properties = props => {
diff --git a/apps/web/src/stores/app-store.js b/apps/web/src/stores/app-store.js
index 33a5d7eff..366cb1b34 100644
--- a/apps/web/src/stores/app-store.js
+++ b/apps/web/src/stores/app-store.js
@@ -1,5 +1,6 @@
import createStore from "../common/store";
import { db } from "../common";
+import { showPasswordDialog } from "../components/dialogs/passworddialog";
function appStore(set, get) {
return {
@@ -67,6 +68,19 @@ function appStore(set, get) {
if (get().selectedItems.length <= 0) {
get().exitSelectionMode();
}
+ },
+ createVault: function() {
+ return showPasswordDialog("create_vault", password =>
+ db.vault.create(password)
+ );
+ },
+ unlockVault: function() {
+ return showPasswordDialog("unlock_vault", password => {
+ return db.vault
+ .unlock(password)
+ .then(() => true)
+ .catch(() => false);
+ });
}
};
}
diff --git a/apps/web/src/stores/editor-store.js b/apps/web/src/stores/editor-store.js
index 3b1a99ead..e63592d46 100644
--- a/apps/web/src/stores/editor-store.js
+++ b/apps/web/src/stores/editor-store.js
@@ -2,6 +2,7 @@ import createStore from "../common/store";
import { store as noteStore, LIST_TYPES } from "./note-store";
import { store as appStore } from "./app-store";
import { db } from "../common";
+import { showPasswordDialog } from "../components/dialogs/passworddialog";
const SESSION_STATES = {
stale: "stale",
@@ -16,6 +17,7 @@ const DEFAULT_SESSION = {
id: "",
pinned: false,
favorite: false,
+ locked: false,
tags: [],
colors: [],
dateEdited: 0,
@@ -42,10 +44,27 @@ function editorStore(set, get) {
},
openSession: async function(note) {
clearTimeout(get().session.timeout);
- const content = {
- text: note.content.text,
- delta: await db.notes.note(note).delta()
- };
+ let content = {};
+ if (!note.locked) {
+ content = {
+ text: note.content.text,
+ delta: await db.notes.note(note).delta()
+ };
+ } else {
+ const result = await showPasswordDialog("unlock_note", password => {
+ return db.vault
+ .open(note.id, password)
+ .then(note => {
+ content = note.content;
+ return true;
+ })
+ .catch(e => {
+ if (e.message === "ERR_WRNG_PwD") return false;
+ else console.error(e);
+ });
+ });
+ if (!result) return;
+ }
noteStore.getState().setSelectedNote(note.id);
set(state => {
state.session = {
@@ -55,20 +74,31 @@ function editorStore(set, get) {
pinned: note.pinned,
favorite: note.favorite,
colors: note.colors,
+ locked: note.locked,
tags: note.tags,
dateEdited: note.dateEdited,
content,
state: SESSION_STATES.new
};
});
- saveLastOpenedNote(note.id);
+ saveLastOpenedNote(!note.locked ? note.id : undefined);
},
saveSession: function(oldSession) {
set(state => {
state.session.isSaving = true;
});
const { session } = get();
- const { title, id, content, pinned, favorite, tags, colors } = session;
+ const {
+ title,
+ id,
+ content,
+ pinned,
+ favorite,
+ locked,
+ tags,
+ colors
+ } = session;
+
let note = {
content,
title,
@@ -78,7 +108,12 @@ function editorStore(set, get) {
tags,
colors
};
- db.notes.add(note).then(id => {
+
+ const func = locked
+ ? db.vault.save.bind(db.vault)
+ : db.notes.add.bind(db.notes);
+
+ func(note).then(id => {
if (tags.length > 0) updateContext("tags", tags);
if (colors.length > 0) {
updateContext("colors", colors);
@@ -95,7 +130,7 @@ function editorStore(set, get) {
});
notesState.refresh();
- saveLastOpenedNote(id);
+ saveLastOpenedNote(locked ? undefined : id);
// we update favorites only if favorite has changed
if (!oldSession || oldSession.favorite !== session.favorite) {
@@ -126,6 +161,14 @@ function editorStore(set, get) {
saveLastOpenedNote();
noteStore.getState().setSelectedNote(0);
},
+ toggleLocked: function() {
+ const { session } = get();
+ if (session.locked) {
+ noteStore.getState().unlock(session.id);
+ } else {
+ noteStore.getState().lock(session.id);
+ }
+ },
setColor: function(color) {
setTagOrColor(get().session, "colors", color, "color", get().setSession);
},
diff --git a/apps/web/src/stores/note-store.js b/apps/web/src/stores/note-store.js
index b868d9a2d..13095ccd3 100644
--- a/apps/web/src/stores/note-store.js
+++ b/apps/web/src/stores/note-store.js
@@ -1,6 +1,8 @@
import { db } from "../common/index";
import createStore from "../common/store";
import { store as editorStore } from "./editor-store";
+import { store as appStore } from "./app-store";
+import { showPasswordDialog } from "../components/dialogs/passworddialog";
const LIST_TYPES = {
fav: "favorites"
@@ -34,6 +36,7 @@ function noteStore(set, get) {
});
},
setSelectedContext: function(context) {
+ console.log("setting context");
let notes = [];
switch (context.type) {
case "tag":
@@ -75,33 +78,75 @@ function noteStore(set, get) {
await db.notes.note(note).pin();
set(state => {
state.notes = db.notes.group(undefined, true);
- syncEditor(note, "pinned");
+ });
+ syncEditor(note.id, "pinned");
+ },
+ favorite: async function(note) {
+ await db.notes.note(note).favorite();
+ setValue(set, note.id, "favorite", !note.favorite);
+ get().refreshList(LIST_TYPES.fav);
+ },
+ unlock: function(noteId) {
+ showPasswordDialog("unlock_note", password => {
+ return db.vault
+ .remove(noteId, password)
+ .then(() => true)
+ .catch(e => {
+ if (e.message === "ERR_WRNG_PWD") return false;
+ else console.error(e);
+ });
+ }).then(res => {
+ if (res) {
+ setValue(set, noteId, "locked", false);
+ }
});
},
- favorite: async function(note, index) {
- await db.notes.note(note).favorite();
- set(state => {
- if (index < 0 || !index) {
- index = state.notes.items.findIndex(n => n.id === note.id);
- if (index < 0) return;
- }
- state.notes.items[index].favorite = !note.favorite;
- syncEditor(note, "favorite");
- });
- get().refreshList(LIST_TYPES.fav);
+ lock: function lock(noteId) {
+ db.vault
+ .add(noteId)
+ .then(() => {
+ setValue(set, noteId, "locked", true);
+ })
+ .catch(async ({ message }) => {
+ switch (message) {
+ case "ERR_NO_VAULT":
+ return appStore.getState().createVault();
+ case "ERR_VAULT_LOCKED":
+ return appStore.getState().unlockVault();
+ default:
+ return false;
+ }
+ })
+ .then(result => {
+ if (result === true) {
+ lock(noteId);
+ }
+ });
}
};
}
-function syncEditor(note, action) {
+function syncEditor(noteId, action) {
const editorState = editorStore.getState();
- if (editorState.session.id === note.id) {
+ if (editorState.session.id === noteId) {
editorState.setSession(
state => (state.session[action] = !state.session[action])
);
}
}
+function setValue(set, noteId, prop, value) {
+ set(state => {
+ const arr = !state.selectedNotes.length
+ ? state.notes.items
+ : state.selectedNotes;
+ let index = arr.findIndex(n => n.id === noteId);
+ if (index < 0) return;
+ arr[index][prop] = value;
+ });
+ syncEditor(noteId, prop);
+}
+
const [useStore, store] = createStore(noteStore);
export { useStore, store, LIST_TYPES };
diff --git a/apps/web/src/utils/theme.js b/apps/web/src/utils/theme.js
index 9fd60d1ec..3c7908025 100644
--- a/apps/web/src/utils/theme.js
+++ b/apps/web/src/utils/theme.js
@@ -97,6 +97,17 @@ const theme = (colors, shadows) => ({
outline: "none",
boxShadow: 4
}
+ },
+ error: {
+ variant: "forms.default",
+ borderColor: "red",
+ ":focus": {
+ outline: "none",
+ borderColor: "red"
+ },
+ ":hover": {
+ borderColor: "red"
+ }
}
},
text: {
diff --git a/apps/web/src/views/Home.js b/apps/web/src/views/Home.js
index 14628b5bf..7c4aa6413 100644
--- a/apps/web/src/views/Home.js
+++ b/apps/web/src/views/Home.js
@@ -64,6 +64,7 @@ function Home() {
notes.groupCounts[groupIndex] && (
diff --git a/apps/web/src/views/Notes.js b/apps/web/src/views/Notes.js
index 0ab596fe6..25ece7634 100644
--- a/apps/web/src/views/Notes.js
+++ b/apps/web/src/views/Notes.js
@@ -16,9 +16,12 @@ const Notes = props => {
clearSelectedContext();
};
}, [clearSelectedContext]);
+ console.log("refreshing notesssss", selectedNotes);
return (
}
+ item={index => (
+
+ )}
itemsLength={selectedNotes.length}
button={{
content: "Make a new note",
diff --git a/apps/web/yarn.lock b/apps/web/yarn.lock
index b426f80a8..172b05c78 100644
--- a/apps/web/yarn.lock
+++ b/apps/web/yarn.lock
@@ -6877,7 +6877,7 @@ normalize-url@^3.0.0, normalize-url@^3.0.1:
"notes-core@https://github.com/thecodrr/notes-core.git":
version "1.2.0"
- resolved "https://github.com/thecodrr/notes-core.git#5ee5dfbd5df2abb748cc1a6b8eae6bdad234dba3"
+ resolved "https://github.com/thecodrr/notes-core.git#ad90f7747165db301cff457b0f702a147977ca47"
dependencies:
fast-sort "^2.0.1"
fuzzysearch "^1.0.3"