Skip to content

Commit

Permalink
Merge pull request #252 from cabcookie:improve-inbox
Browse files Browse the repository at this point in the history
Verarbeiten der Inbox optimieren
  • Loading branch information
cabcookie authored Nov 23, 2024
2 parents 358225f + 515b73f commit 2a61984
Show file tree
Hide file tree
Showing 40 changed files with 980 additions and 1,048 deletions.
9 changes: 7 additions & 2 deletions amplify/data/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ const schema = a
...planningSchema,
...prayerSchema,
...projectSchema,
InboxStatus: a.enum(["new", "done"]),
Inbox: a
.model({
owner: a
Expand All @@ -61,10 +62,14 @@ const schema = a
note: a.string(),
formatVersion: a.integer().default(1),
noteJson: a.json(),
status: a.id().required(),
status: a.ref("InboxStatus").required(),
movedToActivityId: a.string(),
movedToPersonLearningId: a.string(),
createdAt: a.datetime().required(),
})
.secondaryIndexes((inbox) => [inbox("status")])
.secondaryIndexes((inbox) => [
inbox("status").sortKeys(["createdAt"]).queryField("byStatus"),
])
.authorization((allow) => [allow.owner()]),
Meeting: a
.model({
Expand Down
8 changes: 5 additions & 3 deletions api/helpers/activity.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { type Schema } from "@/amplify/data/resource";
import { newDateTimeString } from "@/helpers/functional";
import { newDateTimeString, toISODateTimeString } from "@/helpers/functional";
import { generateClient } from "aws-amplify/data";
import { handleApiErrors } from "../globals";
const client = generateClient<Schema>();

export const createActivityApi = async () => {
export const createActivityApi = async (createdAt?: Date) => {
const { data, errors } = await client.models.Activity.create({
formatVersion: 3,
noteBlockIds: [],
finishedOn: newDateTimeString(),
finishedOn: !createdAt
? newDateTimeString()
: toISODateTimeString(createdAt),
notes: null,
notesJson: null,
});
Expand Down
179 changes: 145 additions & 34 deletions api/useInbox.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,29 @@
import { type Schema } from "@/amplify/data/resource";
import {
addActivityIdToInbox,
createNoteBlock,
updateMovedItemToPersonId,
} from "@/components/inbox/helpers";
import {
LIST_TYPES,
stringifyBlock,
} from "@/components/ui-elements/editors/helpers/blocks";
import { newDateTimeString, toISODateString } from "@/helpers/functional";
import { transformNotesVersion } from "@/helpers/ui-notes-writer";
import { JSONContent } from "@tiptap/core";
import { Editor, JSONContent } from "@tiptap/core";
import { generateClient } from "aws-amplify/data";
import { debounce } from "lodash";
import { compact } from "lodash/fp";
import useSWR from "swr";
import { handleApiErrors } from "./globals";
import {
createActivityApi,
createProjectActivityApi,
updateActivityBlockIds,
} from "./helpers/activity";
const client = generateClient<Schema>();

export type HandleMutationFn = (item: Inbox, callApi?: boolean) => void;

const STATUS_LIST = [
"new",
"actionable",
"notActionable",
"doNow",
"moveToProject",
"clarifyAction",
"clarifyDeletion",
"done",
] as const;

export type InboxStatus = (typeof STATUS_LIST)[number];

const isValidInboxStatus = (status: string): status is InboxStatus =>
STATUS_LIST.includes(status as InboxStatus);

const mapStatus = (status: string): InboxStatus =>
isValidInboxStatus(status) ? status : "new";
type InboxStatus = Schema["InboxStatus"]["type"];

export type Inbox = {
id: string;
Expand All @@ -35,9 +33,20 @@ export type Inbox = {
updatedAt: Date;
};

type ApiResponse = Promise<string | undefined>;
type UpdateInboxFn = (id: string, editor: Editor) => ApiResponse;

export const debouncedOnChangeInboxNote = debounce(
async (id: string, editor: Editor, updateNote: UpdateInboxFn) => {
const data = await updateNote(id, editor);
if (!data) return;
},
1500
);

type MapInboxFn = (data: Schema["Inbox"]["type"]) => Inbox;

export const mapInbox: MapInboxFn = ({
const mapInbox: MapInboxFn = ({
id,
note,
createdAt,
Expand All @@ -47,7 +56,7 @@ export const mapInbox: MapInboxFn = ({
updatedAt,
}) => ({
id,
status: mapStatus(status),
status,
note: transformNotesVersion({
formatVersion,
notes: note,
Expand All @@ -58,17 +67,18 @@ export const mapInbox: MapInboxFn = ({
});

const fetchInbox = async () => {
const { data, errors } = await client.models.Inbox.listInboxByStatus({
status: "new",
});
const { data, errors } = await client.models.Inbox.byStatus(
{
status: "new",
},
{ sortDirection: "ASC" }
);
if (errors) {
handleApiErrors(errors, "Error loading inbox items");
throw errors;
}
try {
return data
.map(mapInbox)
.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
return data.map(mapInbox);
} catch (error) {
console.error("fetchInbox", { error });
throw error;
Expand All @@ -83,18 +93,119 @@ const useInbox = () => {
mutate,
} = useSWR("/api/inbox", fetchInbox);

const handleMutation: HandleMutationFn = (item, callApi = true) => {
const updated: Inbox[] | undefined = inbox?.map((i) =>
i.id !== item.id ? i : item
const createInboxItem = async (note: JSONContent) => {
const updated = [
...(inbox ?? []),
{
id: "new",
status: "new",
note,
createdAt: new Date(),
} as Inbox,
];
if (updated) mutate(updated, false);
const { data, errors } = await client.models.Inbox.create({
noteJson: JSON.stringify(note),
note: null,
formatVersion: 2,
status: "new",
createdAt: newDateTimeString(),
});
if (errors) handleApiErrors(errors, "Error creating inbox item");
if (updated) mutate(updated);
return data;
};

const setInboxItemDone = async (itemId: string) => {
const updated = inbox?.filter((i) => i.id !== itemId);
if (updated) mutate(updated, false);
const { data, errors } = await client.models.Inbox.update({
id: itemId,
status: "done",
});
if (errors) handleApiErrors(errors, "Error updating inbox item");
if (updated) mutate(updated);
return data;
};

const updateNote = async (id: string, editor: Editor) => {
const note = editor.getJSON();
const updated = inbox?.map((item) =>
item.id !== id
? item
: {
...item,
note,
}
);
if (updated) mutate(updated, callApi);
if (updated) mutate(updated, false);
const { data, errors } = await client.models.Inbox.update({
id,
note: null,
formatVersion: 2,
noteJson: JSON.stringify(note),
});
if (errors) handleApiErrors(errors, "Error updating inbox item");
if (updated) mutate(updated);
return data?.id;
};

const moveItemToProject = async (item: Inbox, projectId: string) => {
const activity = await createActivityApi(item.createdAt);
if (!activity) return;

const updated = inbox?.filter((i) => i.id !== item.id);
if (updated) mutate(updated, false);
const blocks = item.note.content;
if (blocks) {
const blockIds = await Promise.all(
blocks.flatMap((block) =>
LIST_TYPES.includes(block.type ?? "")
? block.content?.map((subBlock) =>
createNoteBlock(activity.id, subBlock, block.type)
)
: createNoteBlock(activity.id, block)
)
);
await updateActivityBlockIds(activity.id, compact(blockIds));
}

await createProjectActivityApi(projectId, activity.id);
const itemId = await addActivityIdToInbox(item.id, activity.id);

if (updated) mutate(updated);
return itemId;
};

const moveItemToPerson = async (
item: Inbox,
personId: string,
withPrayer?: boolean
) => {
const updated = inbox?.filter((i) => i.id !== item.id);
if (updated) mutate(updated, false);
const { data, errors } = await client.models.PersonLearning.create({
personId,
learnedOn: toISODateString(item.createdAt),
learning: stringifyBlock(item.note),
prayer: !withPrayer ? undefined : "PRAYING",
});
if (errors) handleApiErrors(errors, "Error moving inbox item to person");
if (updated) mutate(updated);
if (!data) return;
await updateMovedItemToPersonId(item.id, data.id);
return data.id;
};

return {
inbox,
error,
isLoading,
mutate: handleMutation,
createInboxItem,
updateNote,
setInboxItemDone,
moveItemToProject,
moveItemToPerson,
};
};

Expand Down
44 changes: 0 additions & 44 deletions api/useInboxItem.ts

This file was deleted.

Loading

0 comments on commit 2a61984

Please sign in to comment.