Skip to content

Commit

Permalink
Merge pull request #103 from cabcookie:search-and-inbox-improvements
Browse files Browse the repository at this point in the history
# Kleinere Veränderungen

- Bei Suchen nach Personen, Accounts und Projekten musste auf Groß- und Kleinschreibung geachtet werden. Das ist nun nicht mehr so.
- Actions mit Bullet Points sahen in der Vorschau bei einem geschlossenen Accordion etwas komisch aus und waren mit doppelten Kommas durchsät. Das ist jetzt nicht mehr so.
- Das Erstellen eines neuen Eintrags in der Inbox ist in das Navigationsmenü und in den Header verlegt worden.
  • Loading branch information
cabcookie authored Jun 4, 2024
2 parents 19c8ca2 + 4ca37da commit a510c39
Show file tree
Hide file tree
Showing 12 changed files with 245 additions and 61 deletions.
16 changes: 4 additions & 12 deletions api/useInbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,17 +71,6 @@ const useInbox = () => {
mutate,
} = useSWR("/api/inbox", fetchInbox);

const createInbox = async (note: EditorJsonContent) => {
const { data, errors } = await client.models.Inbox.create({
noteJson: JSON.stringify(note),
note: null,
formatVersion: 2,
status: "new",
});
if (errors) handleApiErrors(errors, "Error creating inbox item");
return data?.id;
};

const updateNote = async (id: string, note: EditorJsonContent) => {
const updated = inbox?.map((item) =>
item.id !== id ? item : { ...item, note }
Expand All @@ -98,11 +87,14 @@ const useInbox = () => {
return data?.id;
};

const mutateInbox = (newItem?: Inbox) =>
inbox && mutate([...inbox, ...(newItem ? [newItem] : [])]);

return {
inbox,
errorInbox,
createInbox,
updateNote,
mutateInbox,
};
};

Expand Down
2 changes: 0 additions & 2 deletions components/activities/activity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ const ActivityComponent: FC<ActivityComponentProps> = ({
showDates,
showMeeting,
showProjects,
autoFocus,
allowAddingProjects,
}) => {
const { activity, updateNotes, updateDate, addProjectToActivity } =
Expand Down Expand Up @@ -139,7 +138,6 @@ const ActivityComponent: FC<ActivityComponentProps> = ({
<NotesWriter
notes={activity?.notes}
saveNotes={handleNotesUpdate}
autoFocus={autoFocus}
key={activityId}
/>
</div>
Expand Down
6 changes: 5 additions & 1 deletion components/combo-box/combo-box.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,11 @@ const ComboBox: FC<ComboBoxProps> = ({
<Command
loop
filter={(val, search) =>
val.includes(search) ? 1 : val === "create-new-record" ? 1 : 0
val.toLowerCase().includes(search.toLowerCase())
? 1
: val === "create-new-record"
? 1
: 0
}
>
<CommandInput
Expand Down
30 changes: 30 additions & 0 deletions components/header/CreateInboxItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Plus } from "lucide-react";
import { useCreateInboxItemContext } from "../inbox/CreateInboxItemDialog";
import { Button } from "../ui/button";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "../ui/tooltip";

const CreateInboxItem = () => {
const { open } = useCreateInboxItemContext();

return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="ghost" onClick={open}>
<Plus className="text-[--context-color]" />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Create a new inbox item</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
};

export default CreateInboxItem;
4 changes: 2 additions & 2 deletions components/header/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Context } from "@/contexts/ContextContext";
import { FC } from "react";
import CreateInboxItem from "./CreateInboxItem";
import Logo from "./Logo";
import ProfilePicture from "./ProfilePicture";
import SearchBar from "./SearchBar";

type HeaderProps = {
context?: Context;
Expand All @@ -12,7 +12,7 @@ const Header: FC<HeaderProps> = ({ context }) => (
<div className="border-b sticky top-0 left-0 right-0 z-[45] flex flex-col items-center justify-center bg-bgTransparent h-12 md:h-16 w-full">
<div className="relative flex items-center justify-center w-full xl:w-[80rem]">
<div className="absolute left-2 flex items-center">
<SearchBar />
<CreateInboxItem />
</div>
<Logo context={context} />
<div className="absolute right-2 flex items-center">
Expand Down
145 changes: 145 additions & 0 deletions components/inbox/CreateInboxItemDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import { type Schema } from "@/amplify/data/resource";
import { handleApiErrors } from "@/api/globals";
import useInbox from "@/api/useInbox";
import { generateClient } from "aws-amplify/data";
import { FC, ReactNode, createContext, useContext, useState } from "react";
import NotesWriter, {
EditorJsonContent,
getTextFromEditorJsonContent,
} from "../ui-elements/notes-writer/NotesWriter";
import { Button } from "../ui/button";
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "../ui/dialog";
import { useToast } from "../ui/use-toast";

const client = generateClient<Schema>();

interface CreateInboxItemContextType {
state: boolean;
open: () => void;
close: () => void;
inboxItemText: EditorJsonContent | undefined;
setInboxItemText: (val: { json: EditorJsonContent } | undefined) => void;
createInboxItem: () => Promise<string | undefined>;
}

interface CreateInobxItemProviderProps {
children: ReactNode;
}

export const CreateInboxItemProvider: FC<CreateInobxItemProviderProps> = ({
children,
}) => {
const [isOpen, setIsOpen] = useState(false);
const { mutateInbox } = useInbox();
const [inboxItemText, setInboxItemText] = useState<
EditorJsonContent | undefined
>();
const { toast } = useToast();

const handleUpdate = (val: { json: EditorJsonContent } | undefined) =>
val && setInboxItemText(val.json);

const createInboxItem = async () => {
if (!inboxItemText) return;
const { data, errors } = await client.models.Inbox.create({
noteJson: JSON.stringify(inboxItemText),
note: null,
formatVersion: 2,
status: "new",
});
if (errors) handleApiErrors(errors, "Error creating inbox item");
if (!data) return;
toast({
title: "New Inbox Item Created",
description: getTextFromEditorJsonContent(inboxItemText),
});
mutateInbox({
id: crypto.randomUUID(),
createdAt: new Date(),
status: "new",
note: inboxItemText,
});
setInboxItemText(undefined);
setIsOpen(false);
return data.id;
};

return (
<CreateInboxItemContext.Provider
value={{
state: isOpen,
open: () => setIsOpen(true),
close: () => setIsOpen(false),
inboxItemText,
setInboxItemText: handleUpdate,
createInboxItem,
}}
>
{children}
</CreateInboxItemContext.Provider>
);
};

const CreateInboxItemContext = createContext<
CreateInboxItemContextType | undefined
>(undefined);

export const useCreateInboxItemContext = () => {
const context = useContext(CreateInboxItemContext);
if (!context)
throw new Error(
"useCreateInboxItemContext must be used within CreateInboxItemProvider"
);
return context;
};

const CreateInboxItemDialog = () => {
const {
state,
open,
close,
inboxItemText,
setInboxItemText,
createInboxItem,
} = useCreateInboxItemContext();

return (
<Dialog open={state} onOpenChange={() => (state ? close() : open())}>
<DialogContent className="sm:max-w-[425px] md:max-w-[600px]">
<DialogHeader>
<DialogTitle>Create a New Inbox Item</DialogTitle>
<DialogDescription>
Get it out of your head so you can process and organize it later and
continue to focus on what matters now.
</DialogDescription>
</DialogHeader>
<NotesWriter
notes={inboxItemText || ""}
placeholder="What's on your mind?"
saveNotes={(serializer) => setInboxItemText(serializer())}
showSaveStatus={false}
autoFocus
/>
{JSON.stringify(inboxItemText)}
<DialogFooter>
<Button onClick={createInboxItem}>Save Item</Button>
<DialogClose asChild>
<Button type="button" variant="secondary">
Close
</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
);
};

export default CreateInboxItemDialog;
20 changes: 17 additions & 3 deletions components/layouts/MainLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import { addKeyDownListener } from "@/helpers/keyboard-events/main-layout";
import Head from "next/head";
import { useRouter } from "next/router";
import { FC, ReactNode, useEffect } from "react";
import CreateInboxItemDialog, {
CreateInboxItemProvider,
useCreateInboxItemContext,
} from "../inbox/CreateInboxItemDialog";
import { Toaster } from "../ui/toaster";

type MainLayoutProps = CategoryTitleProps & {
Expand All @@ -27,13 +31,20 @@ const MainLayoutInner: FC<MainLayoutProps> = ({
...categoryTitleProps
}) => {
const { toggleMenu } = useNavMenuContext();
const { open: openCreateInboxItemDialog } = useCreateInboxItemContext();
const { context: storedContext, setContext } = useContextContext();
const context = propsContext || storedContext || "family";
const router = useRouter();

useEffect(
() => addKeyDownListener(router, setContext, toggleMenu),
[router, setContext, toggleMenu]
() =>
addKeyDownListener(
router,
setContext,
toggleMenu,
openCreateInboxItemDialog
),
[openCreateInboxItemDialog, router, setContext, toggleMenu]
);

return (
Expand All @@ -56,6 +67,7 @@ const MainLayoutInner: FC<MainLayoutProps> = ({
</div>
</div>
<Toaster />
<CreateInboxItemDialog />
</main>
</div>
</div>
Expand All @@ -64,7 +76,9 @@ const MainLayoutInner: FC<MainLayoutProps> = ({

const MainLayout: FC<MainLayoutProps> = (props) => (
<NavMenuContextProvider>
<MainLayoutInner {...props} />
<CreateInboxItemProvider>
<MainLayoutInner {...props} />
</CreateInboxItemProvider>
</NavMenuContextProvider>
);

Expand Down
7 changes: 7 additions & 0 deletions components/navigation-menu/NavigationMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { useContextContext } from "@/contexts/ContextContext";
import { useNavMenuContext } from "@/contexts/NavMenuContext";
import { Plus } from "lucide-react";
import { useRouter } from "next/router";
import { BiConversation } from "react-icons/bi";
import { GoTasklist } from "react-icons/go";
import { IconType } from "react-icons/lib";
import { PiHandFist } from "react-icons/pi";
import { useCreateInboxItemContext } from "../inbox/CreateInboxItemDialog";
import {
CommandDialog,
CommandEmpty,
Expand All @@ -28,6 +30,7 @@ type NavigationItem = {
const NavigationMenu = () => {
const { isWorkContext } = useContextContext();
const { menuIsOpen, toggleMenu } = useNavMenuContext();
const { open: openCreateInboxItemDialog } = useCreateInboxItemContext();
const router = useRouter();

const mainNavigation: NavigationItem[] = [
Expand Down Expand Up @@ -103,6 +106,10 @@ const NavigationMenu = () => {
</CommandItem>
))}
</CommandGroup>
<CommandItem forceMount onSelect={openCreateInboxItemDialog}>
<Plus className="mr-2 h-4 w-4" />
<span>Create Inbox Item</span>
</CommandItem>
<CommandItem onSelect={() => {}}>
<div className="px-2 text-muted-foreground text-xs">
<Version />
Expand Down
13 changes: 11 additions & 2 deletions components/ui-elements/notes-writer/NotesWriter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type GenericObject = { [key: string]: any };
const MyExtensions = [StarterKit, Highlight, Link];

export const getTextFromEditorJsonContent = (json: EditorJsonContent) =>
generateText(json, MyExtensions).split("\n\n").join(", ");
generateText(json, MyExtensions);

const compareNotes = (obj1: GenericObject, obj2: GenericObject): boolean => {
for (const key in obj1) {
Expand Down Expand Up @@ -72,6 +72,7 @@ type NotesWriterProps = {
placeholder?: string;
onSubmit?: (item: EditorJsonContent) => void;
readonly?: boolean;
showSaveStatus?: boolean;
};

const NotesWriter: FC<NotesWriterProps> = ({
Expand All @@ -81,6 +82,7 @@ const NotesWriter: FC<NotesWriterProps> = ({
placeholder = "Start taking notes...",
onSubmit,
readonly,
showSaveStatus = true,
}) => {
const editor = useEditor({
extensions: [
Expand Down Expand Up @@ -122,14 +124,21 @@ const NotesWriter: FC<NotesWriterProps> = ({
attributes: {
class: cn(
"prose w-full max-w-full text-notesEditor rounded-md p-2 bg-inherit transition duration-1000 ease",
!isUpToDate(notes, editor.getJSON()) && "bg-destructive/10"
showSaveStatus &&
!isUpToDate(notes, editor.getJSON()) &&
"bg-destructive/10"
),
},
},
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [editor?.getJSON(), notes]);

useEffect(() => {
if (editor?.isActive && autoFocus && !editor?.isFocused)
editor.commands.focus();
}, [editor?.commands, editor?.isActive, editor?.isFocused, autoFocus]);

return <EditorContent editor={editor} />;
};

Expand Down
Loading

0 comments on commit a510c39

Please sign in to comment.