Skip to content

Commit

Permalink
Merge pull request #67 from cabcookie/add-rich-text-editor
Browse files Browse the repository at this point in the history
Allow inbox processing
  • Loading branch information
cabcookie authored May 21, 2024
2 parents 8824de2 + 265d9ec commit 223607c
Show file tree
Hide file tree
Showing 22 changed files with 571 additions and 120 deletions.
7 changes: 4 additions & 3 deletions amplify/data/resource.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type ClientSchema, a, defineData } from "@aws-amplify/backend";
import { a, defineData, type ClientSchema } from "@aws-amplify/backend";

const schema = a.schema({
Context: a.enum(["family", "hobby", "work"]),
Expand All @@ -18,9 +18,10 @@ const schema = a.schema({
note: a.string(),
formatVersion: a.integer().default(1),
noteJson: a.json(),
done: a.id().required(),
status: a.id().required(),
movedToActivityId: a.string(),
})
.secondaryIndexes((inbox) => [inbox("done")])
.secondaryIndexes((inbox) => [inbox("status")])
.authorization((allow) => [allow.owner()]),
DayPlan: a
.model({
Expand Down
7 changes: 3 additions & 4 deletions api/useCrmProjects.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { type Schema } from "@/amplify/data/resource";
import { SelectionSet, generateClient } from "aws-amplify/data";
import useSWR from "swr";
import { flow } from "lodash/fp";
import {
addDaysToDate,
getDayOfDate,
toISODateString,
} from "@/helpers/functional";
import { SelectionSet, generateClient } from "aws-amplify/data";
import { flow } from "lodash/fp";
import useSWR from "swr";
const client = generateClient<Schema>();

export type CrmStage =
Expand Down Expand Up @@ -126,7 +126,6 @@ const useCrmProjects = () => {
data: crmProjects,
error: errorCrmProjects,
isLoading: loadingCrmProjects,
mutate,
} = useSWR("/api/crm-projects/", fetchCrmProjects);

return { crmProjects, errorCrmProjects, loadingCrmProjects };
Expand Down
131 changes: 112 additions & 19 deletions api/useInbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,37 @@ import useSWR from "swr";
import { handleApiErrors } from "./globals";
const client = generateClient<Schema>();

export type InboxStatus =
| "new"
| "actionable"
| "notActionable"
| "doNow"
| "moveToProject"
| "clarifyDeletion"
| "clarifyAction"
| "done";

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

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

const mapStatus = (status: string): InboxStatus =>
isValidInboxStatus(status) ? status : "new";

export type Inbox = {
id: string;
note: EditorJsonContent;
status: InboxStatus;
createdAt: Date;
};

Expand All @@ -21,9 +49,11 @@ const mapInbox: MapInboxFn = ({
note,
createdAt,
formatVersion,
status,
noteJson,
}) => ({
id,
status: mapStatus(status),
note: transformNotesVersion({
version: formatVersion,
notes: note,
Expand All @@ -32,29 +62,30 @@ const mapInbox: MapInboxFn = ({
createdAt: new Date(createdAt),
});

const fetchInbox = async () => {
const { data, errors } = await client.models.Inbox.listInboxByDone({
done: "false",
const fetchInbox = (status: InboxStatus) => async () => {
const { data, errors } = await client.models.Inbox.listInboxByStatus({
status,
});
if (errors) throw errors;
return data
.map(mapInbox)
.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
};

const useInbox = () => {
const useInbox = (status?: InboxStatus) => {
const {
data: inbox,
error: errorInbox,
mutate,
} = useSWR("/api/inbox", fetchInbox);
} = useSWR(`/api/inbox/${status}`, fetchInbox(status || "new"));

const createInbox = async (note: EditorJsonContent) => {
const updated: Inbox[] = [
...(inbox || []),
{
id: crypto.randomUUID(),
note,
status: "new",
createdAt: new Date(),
},
];
Expand All @@ -63,25 +94,13 @@ const useInbox = () => {
noteJson: JSON.stringify(note),
note: null,
formatVersion: 2,
done: "false",
status: "new",
});
if (errors) handleApiErrors(errors, "Error creating inbox item");
mutate(updated);
return data?.id;
};

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

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

return { inbox, errorInbox, createInbox, finishItem, updateNote };
const moveInboxItemToProject = async (
inboxId: string,
createdAt: Date,
notes: EditorJsonContent,
projectId: string
) => {
const { data: activity, errors: activityErrors } =
await client.models.Activity.create({
finishedOn: createdAt.toISOString(),
formatVersion: 2,
notes: null,
notesJson: JSON.stringify(notes),
});
if (activityErrors)
return handleApiErrors(
activityErrors,
"Error creating activity with inbox notes"
);
if (!activity) return;

const { errors: projectActivityErrors } =
await client.models.ProjectActivity.create({
activityId: activity.id,
projectsId: projectId,
});
if (projectActivityErrors)
return handleApiErrors(
projectActivityErrors,
"Error linking activity with project"
);

const { data, errors } = await client.models.Inbox.update({
id: inboxId,
status: "done",
movedToActivityId: activity.id,
});
if (errors)
return handleApiErrors(errors, "Error updating status of inbox item");

return data?.id;
};

const updateStatus = async (id: string, status: InboxStatus) => {
const updated = inbox?.map((item) =>
item.id !== id ? item : { ...item, status }
);
mutate(updated, false);
const { data, errors } = await client.models.Inbox.update({ id, status });
if (errors) handleApiErrors(errors, "Can't update status");
mutate(updated);
return data?.id;
};

const makeActionable = (id: string) => updateStatus(id, "actionable");
const makeNonActionable = (id: string) => updateStatus(id, "notActionable");
const doNow = (id: string) => updateStatus(id, "doNow");
const clarifyAction = (id: string) => updateStatus(id, "clarifyAction");
const isDone = (id: string) => updateStatus(id, "done");
const moveToProject = (id: string) => updateStatus(id, "moveToProject");
const clarifyDeletion = (id: string) => updateStatus(id, "clarifyDeletion");

return {
inbox,
errorInbox,
createInbox,
updateNote,
makeActionable,
makeNonActionable,
doNow,
clarifyAction,
isDone,
moveToProject,
clarifyDeletion,
moveInboxItemToProject,
};
};

export default useInbox;
6 changes: 3 additions & 3 deletions components/CategoryTitle.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { IoChevronBackOutline } from "react-icons/io5";
import styles from "./CategoryTitle.module.css";
import { useRouter } from "next/router";
import { ChangeEvent, FC, useEffect, useRef, useState } from "react";
import SubmitButton from "./ui-elements/submit-button";
import { IoChevronBackOutline } from "react-icons/io5";
import styles from "./CategoryTitle.module.css";
import SubmitButton from "./ui-elements/buttons/submit-button";

export type CategoryTitleProps = {
title?: string;
Expand Down
2 changes: 1 addition & 1 deletion components/dayplan/dayplan-form.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { FC, FormEvent, useState } from "react";
import SubmitButton from "../ui-elements/buttons/submit-button";
import DateSelector from "../ui-elements/date-selector";
import SubmitButton from "../ui-elements/submit-button";
import styles from "./DayPlan.module.css";

type DayPlanFormProps = {
Expand Down
8 changes: 4 additions & 4 deletions components/dayplan/task.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { type Schema } from "@/amplify/data/resource";
import { DayPlanTodo } from "@/api/useDayplans";
import { FC, FormEvent, useState } from "react";
import styles from "./Task.module.css";
import { IoCheckboxSharp, IoSquareOutline } from "react-icons/io5";
import ProjectName from "../ui-elements/tokens/project-name";
import { DayPlanTodo } from "@/api/useDayplans";
import SubmitButton from "../ui-elements/buttons/submit-button";
import ProjectSelector from "../ui-elements/project-selector";
import SubmitButton from "../ui-elements/submit-button";
import ProjectName from "../ui-elements/tokens/project-name";
import styles from "./Task.module.css";

type TaskProps = {
todo: DayPlanTodo;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,8 @@
.button:hover {
box-shadow: 1px 1px 6px rgba(40, 40, 40, 0.4);
}

.noDecoration {
text-decoration: none;
color: var(--text-color);
}
29 changes: 29 additions & 0 deletions components/ui-elements/buttons/link-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import Link from "next/link";
import { FC, ReactNode } from "react";
import styles from "./Button.module.css";

type LinkButtonProps = {
children: ReactNode;
wrapperClassName?: string;
btnClassName?: string;
href: string;
};

const LinkButton: FC<LinkButtonProps> = ({
children,
wrapperClassName,
btnClassName,
href,
}) => {
return (
<div className={wrapperClassName}>
<Link
className={`${styles.noDecoration} ${btnClassName} ${styles.button}`}
href={href}
>
{children}
</Link>
</div>
);
};
export default LinkButton;
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { FC, ReactNode } from "react";
import styles from "./SubmitButton.module.css";
import styles from "./Button.module.css";

type OnClickType = {
onClick: () => void;
Expand Down
2 changes: 1 addition & 1 deletion components/ui-elements/context-warning/context-warning.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Context, useContextContext } from "@/contexts/ContextContext";
import { FC } from "react";
import SubmitButton from "../buttons/submit-button";
import styles from "./ContextWarning.module.css";
import SubmitButton from "../submit-button";

type ContextWarningProps = {
recordContext?: Context;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import useCrmProject from "@/api/useCrmProject";
import { FC, FormEvent, useState } from "react";
import RecordDetails from "../record-details/record-details";
import SubmitButton from "../submit-button";
import { CrmProject } from "@/api/useCrmProjects";
import {
addDaysToDate,
makeRevenueString,
toLocaleDateString,
} from "@/helpers/functional";
import CrmProjectForm, { CrmProjectOnChangeFields } from "./crm-project-form";
import { CrmProject } from "@/api/useCrmProjects";
import Link from "next/link";
import { FC, FormEvent, useState } from "react";
import SubmitButton from "../buttons/submit-button";
import RecordDetails from "../record-details/record-details";
import CrmProjectForm, { CrmProjectOnChangeFields } from "./crm-project-form";

type CrmProjectDetailsProps = {
projectId: string;
Expand Down
2 changes: 1 addition & 1 deletion components/ui-elements/list-items/ListItem.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
margin-bottom: 1rem;
}

.postCheckbox {
.listItemIcon {
font-size: var(--font-size-x-large);
margin-right: 1rem;
}
Expand Down
Loading

0 comments on commit 223607c

Please sign in to comment.