Skip to content

Commit

Permalink
Merge branch 'harshsbhat:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
aditya-supare authored Dec 22, 2024
2 parents 22893f3 + 62aa588 commit 1070fca
Show file tree
Hide file tree
Showing 45 changed files with 875 additions and 683 deletions.
3 changes: 2 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
# should be updated accordingly.

# Drizzle
DATABASE_URL="postgresql://postgres:password@localhost:5432/sealnotes"
UPSTASH_REDIS_REST_URL=""
UPSTASH_REDIS_REST_TOKEN=""

# Example:
# SERVERVAR="foo"
Expand Down
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,40 @@ SealNotes is an end-to-end encrypted web-based notepad that stores and manages y

- **No Tracking:** Sealnotes does not track user activity or store unnecessary metadata.

## Local Setup

- Clone the repo.

```
git clone https://github.com/harshsbhat/sealnotes.git
cd sealnotes
```

- Install dependencies:

```
pnpm install
```

- Create a `.env` file:

```
cp .env.example .env
```

- Create a Redis database with Upstash ( Upstash offers a serverless Redis database with a generous free tier of up to 10,000 requests per day. That's more than enough.) Add the following environment variables:

```
UPSTASH_REDIS_REST_URL=""
UPSTASH_REDIS_REST_TOKEN=""
```

- Run the project:

```
pnpm dev
```

## License

This project is licensed under the [MIT License](https://github.com/harshsbhat/sealnotes?tab=MIT-1-ov-file).
Expand Down
12 changes: 0 additions & 12 deletions drizzle.config.ts

This file was deleted.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
},
"dependencies": {
"@hookform/resolvers": "^3.9.1",
"@radix-ui/react-accordion": "^1.2.2",
"@radix-ui/react-aspect-ratio": "^1.1.0",
"@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-dropdown-menu": "^2.1.3",
Expand Down Expand Up @@ -55,6 +56,7 @@
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"drizzle-orm": "^0.33.0",
"embla-carousel-react": "^8.5.1",
"framer-motion": "^11.13.1",
"geist": "^1.3.0",
"lucide-react": "^0.468.0",
Expand Down
90 changes: 90 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added public/editor.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
44 changes: 0 additions & 44 deletions src/app/[...slug]/ButtonGroup.tsx

This file was deleted.

55 changes: 40 additions & 15 deletions src/app/[...slug]/client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@ import {
import { useToast } from "@/hooks/use-toast";
import { saveNotes } from "@/app/actions/save";
import RichTextEditor from "@/components/editor/Tiptap";
import ButtonGroup from "./ButtonGroup";
import { decrypt, encrypt } from "@/app/utils/vault";
import { fetchData } from "../actions/refresh";
import { decrypt, encrypt, sha256 } from "@/app/utils/vault";
import { refresh } from "../actions/refresh";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
Expand All @@ -27,6 +26,11 @@ import {
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import Link from "next/link";
import { DeleteSite } from "@/components/controlModals/delete-site";
import { ChangePassword } from "@/components/controlModals/change-password";
import LoadingBtn from "@/components/LoadingBtn";


const noteSchema = z.object({
title: z.string(),
Expand All @@ -49,6 +53,7 @@ export function Client({ params, decryptedData, hash }: ClientProps) {
const [isDirty, setIsDirty] = useState<boolean[]>([]);
const [editorContentKeys, setEditorContentKeys] = useState<number[]>([]);
const tabsListRef = useRef<HTMLDivElement>(null);
const [currentInitHash, setCurrentInitHash] = useState(sha256(decryptedData));

const initialTabs: TabsValues = (() => {
try {
Expand Down Expand Up @@ -89,7 +94,7 @@ export function Client({ params, decryptedData, hash }: ClientProps) {

async function onRefresh() {
try {
const currentData = await fetchData(params);
const currentData = await refresh(params);
const decrypted = decrypt(currentData as string, hash);
const refreshedTabs = JSON.parse(decrypted) as { title: string; description: string }[];
toast({
Expand All @@ -100,6 +105,7 @@ export function Client({ params, decryptedData, hash }: ClientProps) {
setValue("tabs", refreshedTabs);
setIsDirty(new Array(refreshedTabs.length).fill(false));
setEditorContentKeys((prevKeys) => prevKeys.map((key) => key + 1));

} catch (error) {
console.error("Refresh error:", error);
toast({
Expand All @@ -112,20 +118,23 @@ export function Client({ params, decryptedData, hash }: ClientProps) {

async function onSubmit(values: { tabs: TabsValues }) {
try {
const encryptedNotes = encrypt(JSON.stringify(values.tabs), hash)
const response = await saveNotes(params, encryptedNotes);
const jsonData = JSON.stringify(values.tabs)
const currentHash = sha256(jsonData);
const encryptedNotes = encrypt(jsonData, hash);
const response = await saveNotes(params, encryptedNotes, currentInitHash, currentHash);
toast({
title: "Success!",
description: response.message,
variant: "default",
});
setIsDirty(new Array(values.tabs.length).fill(false));
setCurrentInitHash(response.currentHash);
} catch (error) {
console.error(error);
toast({
title: "Error",
title: "Error saving your notes",
description:
"An unexpected error occurred. Please contact harsh121102@gmail.com",
"We are unable to save the data at the moment. This is usually because of consecutive write operations. Backup the data and then refresh the page.",
variant: "destructive",
});
}
Expand Down Expand Up @@ -165,18 +174,34 @@ export function Client({ params, decryptedData, hash }: ClientProps) {
}
}
};
function ButtonGroup() {
return (
<div className="flex flex-col sm:flex-row items-center justify-between w-full gap-4 sm:gap-0">
<Link href="/">
<div className="text-lg font-semibold hidden sm:block">
SealNotes
</div>
</Link>

<div className="flex flex-col sm:flex-row sm:justify-end gap-2 w-full sm:w-auto">
<Button variant="outline" className="w-full sm:w-auto" onClick={onRefresh}>
Refresh
</Button>
<ChangePassword params={params} values={JSON.stringify(getValues("tabs"))} currentInitHash={currentInitHash}/>
<LoadingBtn onClick={handleSubmit(onSubmit)} loading={isSubmitting} className="w-full sm:w-auto">
Save
</LoadingBtn>
<DeleteSite params={params} currentInitHash={currentInitHash}/>
</div>
</div>
);
}

return (
<div className="flex justify-center w-full h-[100vh]">
<Form {...form}>
<div className="space-y-6 p-4 w-full max-w-4xl">
<ButtonGroup
onSubmit={handleSubmit(onSubmit)}
onRefresh={onRefresh}
isSubmitting={isSubmitting}
params={params}
values={JSON.stringify(getValues("tabs"))}
/>
<ButtonGroup />
<Tabs
value={activeTab.toString()}
onValueChange={(value: string) => setActiveTab(parseInt(value))}
Expand Down
Loading

0 comments on commit 1070fca

Please sign in to comment.