Skip to content

Commit

Permalink
🔄 Merge pull request #14 from steeeee0223/feature/worxpace
Browse files Browse the repository at this point in the history
Feature/worxpace: complete notion-like documents
  • Loading branch information
steeeee0223 authored Feb 4, 2024
2 parents 48a7df7 + b8c7d69 commit 372752d
Show file tree
Hide file tree
Showing 56 changed files with 2,903 additions and 278 deletions.
10 changes: 9 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,12 @@ CLERK_SECRET_KEY=''
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/

# PRISMA
DB_AUTH=''
DB_WORXPACE=''

# EDGESTORE
EDGE_STORE_ACCESS_KEY=''
EDGE_STORE_SECRET_KEY=''
8 changes: 8 additions & 0 deletions apps/worxpace/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ const config = {
protocol: "https",
hostname: "img.clerk.com",
},
{
protocol: "https",
hostname: "images.unsplash.com",
},
{
protocol: "https",
hostname: "files.edgestore.dev",
},
]
}
};
Expand Down
8 changes: 7 additions & 1 deletion apps/worxpace/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,20 @@
"@acme/prisma": "workspace:*",
"@acme/ui": "workspace:^0.1.0",
"@acme/validators": "workspace:^0.1.0",
"@blocknote/core": "^0.10.1",
"@blocknote/react": "^0.10.1",
"@clerk/nextjs": "^4.29.4",
"@edgestore/react": "^0.1.6",
"@edgestore/server": "^0.1.6",
"@t3-oss/env-nextjs": "^0.7.1",
"next": "^14.0.4",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-textarea-autosize": "^8.5.3",
"sonner": "^1.3.1",
"superjson": "2.2.1",
"zod": "^3.22.4"
"zod": "^3.22.4",
"zustand": "^4.5.0"
},
"devDependencies": {
"@acme/eslint-config": "workspace:^0.2.0",
Expand Down
9 changes: 7 additions & 2 deletions apps/worxpace/src/actions/archive-document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ import {
} from "@acme/ui/lib";
import { DeleteDocument, type DeleteDocumentInput } from "@acme/validators";

import { archive, createAuditLog, fetchClient, UnauthorizedError } from "~/lib";
import {
createAuditLog,
documents,
fetchClient,
UnauthorizedError,
} from "~/lib";

const handler: ActionHandler<DeleteDocumentInput, Modified<Document>> = async (
data,
Expand All @@ -19,7 +24,7 @@ const handler: ActionHandler<DeleteDocumentInput, Modified<Document>> = async (

try {
const { userId, orgId } = fetchClient();
result = await archive({ ...data, userId, orgId });
result = await documents.archive({ ...data, userId, orgId });
/** Activity Log */
await createAuditLog(
{ title: result.item.title, entityId: data.id, type: "DOCUMENT" },
Expand Down
4 changes: 2 additions & 2 deletions apps/worxpace/src/actions/create-document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import { createSafeAction, type ActionHandler } from "@acme/ui/lib";
import { CreateDocument, type CreateDocumentInput } from "@acme/validators";

import {
createDocument as $create,
createAuditLog,
documents,
fetchClient,
UnauthorizedError,
} from "~/lib";
Expand All @@ -18,7 +18,7 @@ const handler: ActionHandler<CreateDocumentInput, Document> = async (data) => {

try {
const { userId, orgId, path } = fetchClient();
result = await $create({ ...data, userId, orgId });
result = await documents.create({ ...data, userId, orgId });
/** Activity Log */
await createAuditLog(
{ title: result.title, entityId: result.id, type: "DOCUMENT" },
Expand Down
13 changes: 9 additions & 4 deletions apps/worxpace/src/actions/delete-document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,21 @@ import {
} from "@acme/ui/lib";
import { DeleteDocument, type DeleteDocumentInput } from "@acme/validators";

import { createAuditLog, fetchClient, remove, UnauthorizedError } from "~/lib";
import {
createAuditLog,
documents,
fetchClient,
UnauthorizedError,
} from "~/lib";

const handler: ActionHandler<DeleteDocumentInput, Modified<Document>> = async (
data,
) => {
let result;

try {
const { userId, orgId } = fetchClient();
result = await remove({ userId, orgId, ...data });
const { userId, orgId, path } = fetchClient();
result = await documents.remove({ userId, orgId, ...data });
/** Activity Log */
await createAuditLog(
{
Expand All @@ -29,13 +34,13 @@ const handler: ActionHandler<DeleteDocumentInput, Modified<Document>> = async (
},
"DELETE",
);
revalidatePath(path);
} catch (error) {
if (error instanceof UnauthorizedError) return { error: "Unauthorized" };
console.log(`ERROR`, error);
return { error: "Failed to delete document." };
}

revalidatePath(`/documents`);
return { data: result };
};

Expand Down
1 change: 1 addition & 0 deletions apps/worxpace/src/actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from "./create-document";
export * from "./archive-document";
export * from "./restore-document";
export * from "./delete-document";
export * from "./update-document";
9 changes: 7 additions & 2 deletions apps/worxpace/src/actions/restore-document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ import {
} from "@acme/ui/lib";
import { DeleteDocument, type DeleteDocumentInput } from "@acme/validators";

import { createAuditLog, fetchClient, restore, UnauthorizedError } from "~/lib";
import {
createAuditLog,
documents,
fetchClient,
UnauthorizedError,
} from "~/lib";

const handler: ActionHandler<DeleteDocumentInput, Modified<Document>> = async (
data,
Expand All @@ -19,7 +24,7 @@ const handler: ActionHandler<DeleteDocumentInput, Modified<Document>> = async (

try {
const { userId, orgId } = fetchClient();
result = await restore({ ...data, userId, orgId });
result = await documents.restore({ ...data, userId, orgId });
/** Activity Log */
await createAuditLog(
{
Expand Down
39 changes: 39 additions & 0 deletions apps/worxpace/src/actions/update-document.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"use server";

import { revalidatePath } from "next/cache";

import type { Document } from "@acme/prisma";
import { createSafeAction, type ActionHandler } from "@acme/ui/lib";
import { UpdateDocument, type UpdateDocumentInput } from "@acme/validators";

import {
createAuditLog,
documents,
fetchClient,
UnauthorizedError,
} from "~/lib";

const handler: ActionHandler<UpdateDocumentInput, Document> = async (data) => {
let result;
const { log, id, ...updateData } = data;

try {
const { userId, orgId } = fetchClient();
result = await documents.update({ userId, orgId, id, ...updateData });
/** Activity Log */
if (log)
await createAuditLog(
{ type: "DOCUMENT", entityId: id, title: result.title },
"UPDATE",
);
} catch (error) {
if (error instanceof UnauthorizedError) return { error: "Unauthorized" };
console.log(`ERROR`, error);
return { error: "Failed to update document." };
}

revalidatePath(`/documents/${data.id}`);
return { data: result };
};

export const updateDocument = createSafeAction(UpdateDocument, handler);
9 changes: 9 additions & 0 deletions apps/worxpace/src/app/(platform)/(public)/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"use client";

import { PropsWithChildren } from "react";

const PublicLayout = ({ children }: PropsWithChildren) => {
return <div className="h-full dark:bg-[#1F1F1F]">{children}</div>;
};

export default PublicLayout;
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"use client";

import { useMemo } from "react";
import dynamic from "next/dynamic";
import { notFound } from "next/navigation";

import type { Document } from "@acme/prisma";
import { Cover } from "@acme/ui/components";
import { useFetch } from "@acme/ui/hooks";
import { cn } from "@acme/ui/lib";

import { getDocument } from "~/app/(platform)/_functions";
import { ToolbarSkeleton } from "~/app/(platform)/(tools)/documents/[documentId]/_component/toolbar";
import { theme } from "~/constants/theme";

interface Params {
params: {
documentId: string;
};
}

const DocumentPage = ({ params: { documentId } }: Params) => {
const {
data: document,
isLoading,
error,
} = useFetch<Document>(
async () => await getDocument(documentId, true),
{
onSuccess: (data) => console.log(`fetched data`, data),
onError: (e) => console.log(e),
},
[documentId],
);
/** Block Note Editor */
const BlockNoteEditor = useMemo(
() => dynamic(() => import("~/components/block-editor"), { ssr: false }),
[],
);

if (error) return notFound();
if (!document || isLoading) return <ToolbarSkeleton />;
return (
<div className="pb-40 dark:bg-[#1F1F1F]">
<Cover preview url={document.coverImage} />
<div className="mx-auto md:max-w-3xl lg:max-w-4xl">
<div className="group relative pl-[54px]">
{!!document.icon && <p className="pt-6 text-6xl">{document.icon}</p>}
<div
className={cn(
theme.flex.gap1,
"py-4 opacity-0 group-hover:opacity-100",
)}
/>
<div className="break-words pb-[11.5px] text-5xl font-bold text-[#3F3F3F] outline-none dark:text-[#CFCFCF]">
{document.title}
</div>
</div>
<BlockNoteEditor editable={false} initialContent={document.content} />
</div>
</div>
);
};

export default DocumentPage;
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"use client";

import Image from "next/image";
import { useOrganization, useUser } from "@clerk/nextjs";
import { PlusCircle } from "lucide-react";
import { toast } from "sonner";

Expand All @@ -11,16 +10,11 @@ import { cn } from "@acme/ui/lib";

import { createDocument } from "~/actions";
import { theme } from "~/constants/theme";
import { useClient } from "~/hooks";

interface Params {
params: { role: string; clientId: string };
}

const Client = ({ params: { role } }: Params) => {
const { user } = useUser();
const { organization } = useOrganization();
const name = role === "organization" ? organization?.name : user?.firstName;

const Client = () => {
const { workspace } = useClient();
/** Action */
const { dispatch } = useTreeAction();
const { execute } = useAction(createDocument, {
onSuccess: (data) => {
Expand All @@ -33,11 +27,10 @@ const Client = ({ params: { role } }: Params) => {
},
onError: (e) => toast.error(e),
});
const onSubmit = () => {
const onSubmit = () =>
execute({ title: "Untitled", parentId: undefined })
.then(() => console.log(`processing`))
.catch((e) => console.log(e));
};

return (
<div
Expand All @@ -60,7 +53,9 @@ const Client = ({ params: { role } }: Params) => {
alt="Empty"
className="hidden dark:block"
/>
<h2 className="text-lg font-medium">Welcome to {name}&apos;s WorXpace</h2>
<h2 className="text-lg font-medium">
Welcome to {workspace}&apos;s WorXpace
</h2>
<form action={onSubmit}>
<Button type="submit">
<PlusCircle className={cn(theme.size.icon, "mr-2")} />
Expand Down
Loading

0 comments on commit 372752d

Please sign in to comment.