middle of refactoring server side backend stuff
parent
1972f9eebf
commit
168df6cfbc
56
src/App.js
56
src/App.js
|
|
@ -1,40 +1,31 @@
|
|||
import React, { PureComponent } from "react";
|
||||
import { connect } from "weedux";
|
||||
|
||||
import { connect, bindActionCreators } from "weedux";
|
||||
import { store, actions } from "./state/index.js";
|
||||
import debounce from "lodash.debounce";
|
||||
|
||||
import NoteList from "./components/NoteList/NoteList";
|
||||
import NoteContent from "./components/NoteContent/NoteContent";
|
||||
import Omnibar from "./components/Omnibar/Omnibar";
|
||||
|
||||
import "./App.css";
|
||||
import { bindActionCreators } from "weedux/lib";
|
||||
import { getNotes } from "./state/api.js";
|
||||
|
||||
class App extends PureComponent {
|
||||
defaultProps = { notes: [] };
|
||||
|
||||
state = { filter: "" };
|
||||
|
||||
async componentDidMount() {
|
||||
const { getNotes } = this.props;
|
||||
getNotes({ filter: "" });
|
||||
}
|
||||
|
||||
handleSearch = text => {
|
||||
const normalizedText = text.toLocaleLowerCase();
|
||||
const { getNotes } = this.props;
|
||||
|
||||
getNotes({ filter: normalizedText });
|
||||
// this.setState({
|
||||
// notes: getNotes().notes.filter(
|
||||
// n =>
|
||||
// n.title.toLocaleLowerCase().includes(normalizedText) ||
|
||||
// n.tags.find(
|
||||
// x => x.toLocaleLowerCase() === normalizedText
|
||||
// ) ||
|
||||
// n.content.toLocaleLowerCase().includes(normalizedText)
|
||||
// )
|
||||
// });
|
||||
};
|
||||
handleSearch = text => this.setState({ filter: text.toLocaleLowerCase() });
|
||||
|
||||
handleCreate = title => {
|
||||
const { createNote } = this.props;
|
||||
createNote({ title, content: "", tags: [] });
|
||||
getNotes();
|
||||
};
|
||||
|
||||
handleSelectNote = title => {
|
||||
|
|
@ -48,13 +39,22 @@ class App extends PureComponent {
|
|||
};
|
||||
|
||||
handleTagUpdate = ({ title, newTags }) => {
|
||||
// const { updateTags } = this.props;
|
||||
// updateTags({ title, tags: newTags });
|
||||
const { updateTags } = this.props;
|
||||
updateTags({ title, tags: newTags });
|
||||
};
|
||||
|
||||
applyFilter = (notes = [], filter = "") =>
|
||||
notes.filter(
|
||||
n =>
|
||||
n.title.toLocaleLowerCase().includes(filter) ||
|
||||
n.tags.find(x => x.toLocaleLowerCase() === filter) ||
|
||||
n.content.toLocaleLowerCase().includes(filter)
|
||||
);
|
||||
|
||||
render() {
|
||||
const { notes, selectedNote } = this.props;
|
||||
console.log(this.props);
|
||||
const { filter } = this.state;
|
||||
const handleSave = debounce(this.handleSaveNoteContent, 250);
|
||||
|
||||
return (
|
||||
<div className="App">
|
||||
|
|
@ -67,25 +67,19 @@ class App extends PureComponent {
|
|||
</section>
|
||||
<section className="NoteArea">
|
||||
<NoteList
|
||||
notes={notes}
|
||||
notes={this.applyFilter(notes, filter)}
|
||||
onSelect={this.handleSelectNote}
|
||||
onTagUpdate={this.handleTagUpdate}
|
||||
selectedNote={selectedNote}
|
||||
/>
|
||||
<NoteContent
|
||||
note={selectedNote}
|
||||
onSave={this.handleSaveNoteContent}
|
||||
/>
|
||||
<NoteContent note={selectedNote} onSave={handleSave} />
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const ms2p = s => {
|
||||
console.log(s);
|
||||
return s;
|
||||
};
|
||||
const ms2p = s => s;
|
||||
|
||||
const md2p = dispatch => bindActionCreators({ ...actions }, dispatch);
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ export default function NoteList({
|
|||
>
|
||||
<NoteListItem
|
||||
{...n}
|
||||
selected={n.title === selectedNoteTitle}
|
||||
onSelect={onSelect}
|
||||
onTagUpdate={onTagUpdate}
|
||||
/>
|
||||
|
|
@ -41,6 +42,7 @@ const NoteListItem = ({
|
|||
content,
|
||||
title,
|
||||
tags,
|
||||
selected = false,
|
||||
lastModified,
|
||||
onSelect,
|
||||
onTagUpdate
|
||||
|
|
@ -50,7 +52,11 @@ const NoteListItem = ({
|
|||
<h2>{title}</h2>
|
||||
<p className="preview">-- {content}</p>
|
||||
<span className="attributes">
|
||||
<TagList tags={tags} onTagUpdate={onTagUpdate} />
|
||||
<TagList
|
||||
canEdit={selected}
|
||||
tags={tags}
|
||||
onTagUpdate={onTagUpdate}
|
||||
/>
|
||||
<span className="lastModified">
|
||||
{formatRelative(new Date(lastModified), new Date())}
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -2,23 +2,27 @@ import React, { Fragment, useState } from "react";
|
|||
import { noop, enterKeyPressed } from "../../utils";
|
||||
import "./TagList.css";
|
||||
|
||||
export default function TagList({ tags = [], onTagUpdate = noop }) {
|
||||
export default function TagList({
|
||||
canEdit = false,
|
||||
tags = [],
|
||||
onTagUpdate = noop
|
||||
}) {
|
||||
const getTags = () => tags.join(",");
|
||||
const [editMode, setEditMode] = useState(false);
|
||||
const [editTags, setEditTags] = useState(getTags());
|
||||
|
||||
const toggleEditMode = () => {
|
||||
setEditMode(!editMode);
|
||||
if (editMode) {
|
||||
if (editMode && canEdit) {
|
||||
onTagUpdate(editTags.split(",").map(x => x.trim()));
|
||||
}
|
||||
setEditMode(!editMode && canEdit);
|
||||
};
|
||||
|
||||
const updateTags = ({ target }) => setEditTags(target.value);
|
||||
|
||||
return (
|
||||
<span className="TagList" onDoubleClick={toggleEditMode}>
|
||||
{editMode ? (
|
||||
{editMode && canEdit ? (
|
||||
<input
|
||||
type="text"
|
||||
style={{ width: `${editTags.length - 2}ch` }}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
const { loadNotesInDirectory, saveNoteInDirectory } = require("./notes");
|
||||
const { defaultSettings } = require("./settings");
|
||||
|
||||
function newNoteBackend(initSettings) {
|
||||
let settings = { ...defaultSettings, ...initSettings };
|
||||
|
||||
async function onNoteCommand({ type, payload }) {
|
||||
console.log(`got command: ${type} -n ${JSON.stringify(payload)}`);
|
||||
const { directory } = settings;
|
||||
switch (type) {
|
||||
case "getNotes":
|
||||
const files = await loadNotesInDirectory(directory);
|
||||
return {
|
||||
type: "getNotes",
|
||||
payload: {
|
||||
notes: files.map(f => ({ ...f, tags: [] }))
|
||||
}
|
||||
};
|
||||
case "saveNote":
|
||||
const { title, content, tags } = payload;
|
||||
const result = await saveNoteInDirectory(settings, {
|
||||
title,
|
||||
content,
|
||||
tags
|
||||
});
|
||||
return { type: "saveNote", payload: result };
|
||||
case "getSettings":
|
||||
case "saveSettings":
|
||||
default:
|
||||
return { type: "noop" };
|
||||
}
|
||||
}
|
||||
|
||||
function updateSettings({ directory }) {
|
||||
settings.directory = directory;
|
||||
}
|
||||
|
||||
return {
|
||||
onNoteCommand,
|
||||
updateSettings
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = { createBackend: newNoteBackend };
|
||||
|
|
@ -116,11 +116,11 @@ async function saveNoteInDirectory(
|
|||
) {
|
||||
let fullPath = path.join(directory, `${title}.${defaultExtension}`);
|
||||
|
||||
const match = await listNotesInDirectory(directory).filter(
|
||||
const match = (await listNotesInDirectory(directory)).filter(
|
||||
f => f.friendlyName === title
|
||||
);
|
||||
|
||||
if (match || match.length > 0) fullPath = match[0].fullPath;
|
||||
if (match && match.length > 0) fullPath = match[0].path;
|
||||
|
||||
tagsCache[title] = tags;
|
||||
return Promise.all([
|
||||
|
|
@ -138,7 +138,7 @@ function newNoteBackend(initSettings) {
|
|||
let settings = { ...defaultSettings, ...initSettings };
|
||||
|
||||
async function onNoteCommand({ type, payload }) {
|
||||
console.log(`got command: ${type}`);
|
||||
console.log(`got command: ${type} -n ${JSON.stringify(payload)}`);
|
||||
const { directory } = settings;
|
||||
switch (type) {
|
||||
case "getNotes":
|
||||
|
|
@ -151,7 +151,7 @@ function newNoteBackend(initSettings) {
|
|||
};
|
||||
case "saveNote":
|
||||
const { title, content, tags } = payload;
|
||||
const result = await saveNoteInDirectory(directory, {
|
||||
const result = await saveNoteInDirectory(settings, {
|
||||
title,
|
||||
content,
|
||||
tags
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
export const defaultSettings = {
|
||||
directory: "./",
|
||||
defaultExtension: "txt"
|
||||
};
|
||||
|
|
@ -34,8 +34,8 @@ contextBridge.exposeInMainWorld("api", {
|
|||
receive,
|
||||
receiveOnce,
|
||||
sendLinkNav: target => ipcRenderer.send("element-clicked", target),
|
||||
getNotes: async ({ filter }) => {
|
||||
send("note_command", { type: "getNotes", payload: { filter } });
|
||||
getNotes: async () => {
|
||||
send("note_command", { type: "getNotes", payload: {} });
|
||||
const response = await receiveOnce("note_response");
|
||||
return JSON.parse(response);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -3,7 +3,13 @@ import {
|
|||
upsertNote as upsertNoteBackend
|
||||
} from "./api";
|
||||
|
||||
export const reducer = (cs, { type, payload }) => {
|
||||
const initialState = {
|
||||
notes: [],
|
||||
selectedNote: null,
|
||||
error: null
|
||||
};
|
||||
|
||||
export const reducer = (cs = initialState, { type, payload }) => {
|
||||
switch (type) {
|
||||
case "SELECT_NOTE":
|
||||
return { ...cs, selectedNote: payload.selectedNote };
|
||||
|
|
@ -27,14 +33,17 @@ export const reducer = (cs, { type, payload }) => {
|
|||
};
|
||||
|
||||
const selectNote = ({ title }) => (dispatch, getState) => {
|
||||
const normalizedTitle = title.toLocaleLowerCase();
|
||||
const { selectedNote, notes } = getState();
|
||||
|
||||
let foundNote = selectedNote;
|
||||
const notesFilter = notes.filter(n => n.title === title);
|
||||
const notesFilter = notes.filter(
|
||||
n => n.title.toLocaleLowerCase() === normalizedTitle
|
||||
);
|
||||
if (notesFilter.length > 0) {
|
||||
foundNote = notesFilter[0];
|
||||
}
|
||||
dispatch({ type: "SELECT_NOTE", payload: { ...foundNote } });
|
||||
dispatch({ type: "SELECT_NOTE", payload: { selectedNote: foundNote } });
|
||||
};
|
||||
|
||||
const deleteNote = ({ title }) => (dispatch, getState) => {};
|
||||
|
|
@ -52,7 +61,7 @@ const createNote = ({ title, content, tags = [] }) => async (
|
|||
}
|
||||
};
|
||||
|
||||
const getNotes = ({ filter }) => async (dispatch, getState) => {
|
||||
const getNotes = () => async (dispatch, getState) => {
|
||||
const { notesLoading } = getState();
|
||||
if (notesLoading) {
|
||||
console.warn(
|
||||
|
|
@ -63,7 +72,7 @@ const getNotes = ({ filter }) => async (dispatch, getState) => {
|
|||
|
||||
dispatch({ type: "GET_NOTES_START" });
|
||||
try {
|
||||
const result = await getNotesBackend({ filter });
|
||||
const result = await getNotesBackend();
|
||||
console.log(result);
|
||||
dispatch({ type: "GET_NOTES_SUCCESS", payload: result });
|
||||
} catch (error) {
|
||||
|
|
@ -71,9 +80,14 @@ const getNotes = ({ filter }) => async (dispatch, getState) => {
|
|||
}
|
||||
};
|
||||
|
||||
const updateTags = ({ title, tags }) => (dispatch, getState) => {
|
||||
console.log(`adding tags ${tags} to ${title}`);
|
||||
};
|
||||
|
||||
export const actions = {
|
||||
getNotes,
|
||||
deleteNote,
|
||||
createNote,
|
||||
selectNote
|
||||
selectNote,
|
||||
updateTags
|
||||
};
|
||||
|
|
|
|||
|
|
@ -14,13 +14,13 @@ const createNote = ({ title = null, content = "", tags = [] }) => {
|
|||
};
|
||||
};
|
||||
|
||||
export const getNotes = async filter => {
|
||||
export const getNotes = async () => {
|
||||
const { api } = window;
|
||||
|
||||
if (!api) return { ...notesStore };
|
||||
|
||||
const { getNotes } = api;
|
||||
const { payload } = await getNotes({ filter });
|
||||
const { payload } = await getNotes();
|
||||
console.log(payload);
|
||||
return {
|
||||
error: null,
|
||||
|
|
@ -29,7 +29,7 @@ export const getNotes = async filter => {
|
|||
};
|
||||
|
||||
export const upsertNote = async ({ title, content, tags }) => {
|
||||
const newNote = createNote({ title });
|
||||
const newNote = createNote({ title, content, tags });
|
||||
const { api } = window;
|
||||
|
||||
if (!api) {
|
||||
|
|
|
|||
30
src/utils.js
30
src/utils.js
|
|
@ -20,35 +20,7 @@ export const createNote = ({ title = null, content = "", tags = [] }) => {
|
|||
};
|
||||
};
|
||||
|
||||
export const getNotes = async filter => {
|
||||
const { api } = window;
|
||||
|
||||
if (!api) return { ...notesStore };
|
||||
|
||||
const { getNotes } = api;
|
||||
const { payload } = await getNotes({ filter });
|
||||
console.log(payload);
|
||||
return {
|
||||
error: null,
|
||||
notes: payload.notes
|
||||
};
|
||||
};
|
||||
|
||||
export const upsertNote = async ({ title, content, tags }) => {
|
||||
const newNote = createNote({ title });
|
||||
const { api } = window;
|
||||
|
||||
if (!api) {
|
||||
notesStore.notes = notesStore.notes.concat(newNote);
|
||||
}
|
||||
|
||||
const { saveNote } = api;
|
||||
await saveNote({ ...newNote });
|
||||
|
||||
return newNote;
|
||||
};
|
||||
|
||||
const notesStore = {
|
||||
export const dev_notes = {
|
||||
error: null,
|
||||
notes: [
|
||||
createNote({
|
||||
|
|
|
|||
Loading…
Reference in New Issue