Skip to content

Commit

Permalink
some plus features added
Browse files Browse the repository at this point in the history
  • Loading branch information
dickeyy committed Jul 28, 2024
1 parent b8aadb1 commit 28e03cd
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 16 deletions.
Binary file modified apps/api/bun.lockb
Binary file not shown.
31 changes: 31 additions & 0 deletions apps/api/src/lib/document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,37 @@ export async function updateDocumentByID(
return doc[0] as any;
}

export async function updateDocumentTitle(id: string, title: string): Promise<DocumentType | null> {
const now = Math.floor(new Date().getTime() / 1000);

const doc = await db.select().from(documents).where(eq(documents.id, id)).limit(1).execute();
if (!doc) {
return null;
}

try {
if (title.length === 0) {
title = "Untitled";
} else if (title.length > 255) {
title = title.substring(0, 255);
}

await db
.update(documents)
.set({ title: title, updated_at: now })
.where(eq(documents.id, id))
.execute();
} catch (e) {
console.error(e);
return null;
}

doc[0].title = title;
doc[0].updated_at = now;
doc[0].content = await decrypt(doc[0].content || "");
return doc[0] as any;
}

export async function deleteDocumentByID(id: string, userID: string): Promise<boolean> {
try {
await db
Expand Down
28 changes: 27 additions & 1 deletion apps/api/src/routes/documents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import {
getDocumentByID,
updateDocumentByID,
deleteDocumentByID,
updateDocumentMetadata
updateDocumentMetadata,
updateDocumentTitle
} from "../lib/document";
import { validateClerkToken } from "../lib/clerk";
import { decrypt } from "../lib/crypto";
Expand Down Expand Up @@ -82,6 +83,31 @@ docs.ws("/ws", {
message: "error"
});
}
} else if (message === "update title") {
if (data.title !== undefined) {
if (user.publicMetadata.plan === "free") {
ws.send({
message: "error"
});
return;
}

const doc = await updateDocumentTitle(data.doc_id, data.title);
if (!doc) {
ws.send({
message: "error"
});
} else {
ws.send({
message: "success",
doc: doc
});
}
} else {
ws.send({
message: "error"
});
}
} else {
ws.send("invalid event");
}
Expand Down
1 change: 0 additions & 1 deletion apps/web/app/entry/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ export default function Page({ params }: { params: { id: string } }) {
return (
<div className="flex h-full w-full items-center justify-center p-4 pb-8">
<Document document={document} />
{/* <WebSocketDemo /> */}
</div>
);
}
14 changes: 7 additions & 7 deletions apps/web/app/pricing/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,24 +41,24 @@ export default function Pricing() {
features={[
"Unlimited entries",
"1 daily entry limit",
"Export to .txt",
"Blur content on command",
"Private and secure"
"Private and secure",
"Export to .txt - Coming soon"
]}
href="/sign-up"
/>
<PricingCard
title="Plus"
price="$4.99"
highlight
interval="/ month"
interval="/month"
description="For the cool user."
features={[
"Everything in the starter plan",
"Toggleable entry lock - Coming soon",
"Unlimited daily entries - Coming soon",
"Edit entry titles - Coming soon",
"Export to .pdf - Coming soon"
"Unlimited daily entries",
"Edit entry titles",
"Export to .pdf - Coming soon",
"Toggleable entry lock - Coming soon"
]}
href="/upgrade"
/>
Expand Down
Binary file modified apps/web/bun.lockb
Binary file not shown.
70 changes: 66 additions & 4 deletions apps/web/components/document.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,20 @@ import ms from "ms";
import { EyeIcon, EyeOffIcon, Trash2Icon } from "lucide-react";
import { debounce, get } from "lodash";
import type { DocumentType } from "@/types/Document";
import { useAuth } from "@clerk/nextjs";
import { useAuth, useUser } from "@clerk/nextjs";
import useDocumentStore from "@/stores/document-store";
import { useRouter } from "next/navigation";
import { toast } from "sonner";
import { Dialog, DialogContent, DialogFooter, DialogHeader } from "@/components/ui/dialog";
import { DialogDescription, DialogTitle } from "@radix-ui/react-dialog";
import useWebSocket from "react-use-websocket";
import { usePlausible } from "next-plausible";
import { Input } from "./ui/input";

export default function Document({ document }: { document?: DocumentType }) {
const { getToken } = useAuth();
const plausible = usePlausible();
const { user } = useUser();

// ws stuff
const [socketUrl, setSocketUrl] = useState(
Expand All @@ -43,6 +45,7 @@ export default function Document({ document }: { document?: DocumentType }) {

const [doc, setDoc] = useState(document);
const [content, setContent] = useState(doc?.content);
const [title, setTitle] = useState(doc?.title);
const [metadata, setMetadata] = useState(doc?.metadata);

const [isSaving, setIsSaving] = useState(false);
Expand Down Expand Up @@ -151,6 +154,35 @@ export default function Document({ document }: { document?: DocumentType }) {
[metadata, doc?.metadata]
);

// save title
const saveTitle = useCallback(
debounce(() => {
getToken()
.then((token: any) => {
if (title !== doc?.title) {
setIsSaving(true);
sendJsonMessage({
message: "update title",
data: {
doc_id: doc?.id || "",
title: title
},
token: token || ""
});
}
})
.catch((err) => {
console.log(err);
toast.error("Error saving document", {
description:
"Something went wrong while trying to authenticate. Please try again.",
duration: 5000
});
});
}, 1000), // Adjust the debounce delay as needed
[title, doc?.title]
);

// handle websocket messages
useEffect(() => {
if (lastMessage !== null) {
Expand All @@ -161,6 +193,17 @@ export default function Document({ document }: { document?: DocumentType }) {
setDocUpdatedAt(new Date().getTime());
setSinceUpdate("just now");
setDoc(JSON.parse(lastMessage.data).doc);

// set the active doc to the new doc and update the documents list to replace the old doc with the new doc
useDocumentStore.setState({
documents: useDocumentStore.getState().documents.map((d) => {
if (d.id === doc?.id) {
return JSON.parse(lastMessage.data).doc;
} else {
return d;
}
})
});
}
} else if (JSON.parse(lastMessage.data).message === "error") {
toast.error("Error saving document", {
Expand Down Expand Up @@ -216,6 +259,16 @@ export default function Document({ document }: { document?: DocumentType }) {
return () => saveMetadata.cancel();
}, [metadata, doc?.metadata, saveMetadata, plausible]);

// Call saveTitle whenever title changes
useEffect(() => {
if (title !== doc?.title) {
saveTitle();
}

// Cancel the debounce on component unmount
return () => saveTitle.cancel();
}, [title, doc?.title, saveTitle]);

return (
<div className="col-span-1 flex min-h-screen w-full flex-col items-start justify-start pt-4">
<nav className="bg-background fixed left-0 top-0 z-10 flex w-full items-center justify-end gap-4 px-8 py-2">
Expand Down Expand Up @@ -380,9 +433,18 @@ export default function Document({ document }: { document?: DocumentType }) {
</DropdownMenu>
</nav>
<div className="mt-[2rem] flex w-full flex-col items-start justify-start md:mx-auto md:w-full md:max-w-full lg:max-w-[50rem] 2xl:max-w-[60rem]">
<p className="text-foreground/60 text-md mb-4 flex-wrap text-left font-mono font-medium ">
{doc?.title}
</p>
{user?.publicMetadata.plan === "free" ? (
<p className="text-foreground/60 text-md mb-4 flex-wrap text-left font-mono font-medium ">
{title}
</p>
) : (
<Input
placeholder="Title"
value={title}
onChange={(e) => setTitle(e.target.value)}
className="text-md text-foreground/60 mb-4 w-full flex-wrap border-0 p-0 text-left font-mono font-medium shadow-none focus-visible:ring-0"
/>
)}
<Editor
content={content || ""}
setContent={setContent}
Expand Down
2 changes: 1 addition & 1 deletion apps/web/components/editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export default function Editor({
}}
>
<PlateContent
className={`w-full border-0 p-0 font-light leading-loose shadow-none focus:outline-none focus-visible:border-0 focus-visible:ring-0
className={`h-fit w-full border-0 p-0 font-light leading-loose shadow-none focus:outline-none focus-visible:border-0 focus-visible:ring-0
${isBlured ? "blur-[8px]" : ""}
${metadata.font === "serif" ? "font-serif" : metadata.font === "sans" ? "font-sans" : "font-mono"}
`}
Expand Down
22 changes: 20 additions & 2 deletions apps/web/components/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import AccountDropdown from "./account-dropdown";
import { ScrollArea } from "./ui/scroll-area";
import useDocumentStore from "@/stores/document-store";
import { useAuth } from "@clerk/nextjs";
import { useAuth, useUser } from "@clerk/nextjs";
import { DocumentType } from "@/types/Document";
import useClerkSWR from "@/lib/clerk-swr";
import { useEffect, useState } from "react";
Expand All @@ -19,6 +19,7 @@ export default function Sidebar() {
const { documents } = useDocumentStore();
const router = useRouter();
const { getToken } = useAuth();
const { user } = useUser();
const { data, error } = useClerkSWR(`${process.env.NEXT_PUBLIC_API_URL}/documents/all`);
const plausible = usePlausible();

Expand All @@ -32,6 +33,21 @@ export default function Sidebar() {

// function to create a new document
const cd = async () => {
if (user?.publicMetadata.plan === "free") {
const documents = useDocumentStore.getState().documents;
// we need to check if the user has already created a document today (if they are free plan)
// to do this, we check the list of documents and see if any doc.created_at unix timestamp is the same date as today
// first sort the documents by created_at
const sortedDocs = documents.sort((a, b) => b.created_at - a.created_at);
const today = new Date();
const mostRecentDocDate = new Date(sortedDocs[0].created_at * 1000);
if (today.getDate() === mostRecentDocDate.getDate()) {
// if the user has already created a document today, we can't create a new one
toast.error("You have already created an entry today");
return;
}
}

const token = await getToken();
createDocument(token || "").then((res) => {
if (res.ok) {
Expand Down Expand Up @@ -83,7 +99,9 @@ export default function Sidebar() {
</div>
</div>

<AccountDropdown />
<div className="fixed bottom-4 flex flex-col items-center">
<AccountDropdown />
</div>
</aside>

{/* mobile view */}
Expand Down

0 comments on commit 28e03cd

Please sign in to comment.