Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

52 render notes from the left side to the main screen #55

Merged
merged 10 commits into from
Dec 4, 2023
7 changes: 0 additions & 7 deletions app/__tests__/navbar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,4 @@ describe("Navbar Component", () => {
expect(screen.getByText(/where's religion?/i)).toBeInTheDocument();
expect(screen.getByRole("navigation")).toBeInTheDocument();
});

it("renders SearchBar component", async () => {
await act(async () => {
render(<Navbar />);
});
expect(screen.getByPlaceholderText(/search.../i)).toBeInTheDocument();
});
});
53 changes: 53 additions & 0 deletions app/__tests__/note_rendering.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import "@testing-library/jest-dom";
import { render, screen } from "@testing-library/react";
import ToolPage from "../lib/components/note_component";

describe("ToolPage", () => {
const testNote = {
id: "1",
title: "Test Note",
text: "<p>Test content for the note</p>",
time: new Date("2023-01-01T12:00:00"),
media: [],
audio: [],
creator: "test_creator",
latitude: "34.0522",
longitude: "-118.2437",
published: false,
tags: ["test", "note"],
};

it("initializes the editor with provided note content", async () => {
render(<ToolPage note={testNote} />);

// Use a regex for partial matching and to ignore case
const content = await screen.findByText(/test content/i);
expect(content).toBeInTheDocument();
});

it("updates editor content when note prop changes", async () => {
const updatedNote = {
id: "2",
title: "Updated Title",
text: "<p>Updated content for the note</p>",
time: new Date(),
media: [],
audio: [],
creator: "updated_creator",
latitude: "40.7128",
longitude: "-74.0060",
published: false,
tags: ["updated", "note"],
};

const { rerender } = render(<ToolPage note={testNote} />);

const initialContent = await screen.findByText(/test content/i);
expect(initialContent).toBeInTheDocument();

rerender(<ToolPage note={updatedNote} />);

const updatedContent = await screen.findByText(/updated content/i);
expect(updatedContent).toBeInTheDocument();
});
});
24 changes: 23 additions & 1 deletion app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,26 @@
body {
@apply bg-background text-foreground;
}
}
}

.custom-input:focus {
border: none !important;
outline: none !important;
box-shadow: none !important;
-webkit-box-shadow: none !important;
-moz-box-shadow: none !important;
padding: none !important;
margin: none !important;
border: none !important;
}
.custom-input {
border: none !important;
outline: none !important;
box-shadow: none !important;
-webkit-box-shadow: none !important;
-moz-box-shadow: none !important;
padding: none !important;
margin: none !important;
border: none !important;
}

4 changes: 0 additions & 4 deletions app/lib/components/navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import React, { useEffect, useState } from "react";
import Link from "next/link";
import { User } from "../models/user_class";
import SearchBar from "./search_bar";
import { Button } from "@/components/ui/button";

const user = User.getInstance();
Expand Down Expand Up @@ -42,9 +41,6 @@ export default function Navbar() {
</a>
</Link>
</div>
<div className="w-full">
<SearchBar />
</div>
<div className="">
{name ? (
<div className="flex items-center gap-6 w-full">
Expand Down
80 changes: 50 additions & 30 deletions app/lib/components/note_component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,40 @@ import {
InstagramLogoIcon,
LinkedInLogoIcon,
} from "@radix-ui/react-icons";
import { Editor, EditorState, RichUtils } from "draft-js";
import { ContentState, Editor, EditorState, RichUtils } from "draft-js";
import "draft-js/dist/Draft.css";
import { useState, useEffect } from "react";
import { stateFromHTML } from "draft-js-import-html";
import { stateToHTML } from "draft-js-export-html";
import { Button } from "@/components/ui/button";
import { Note } from "@/app/types";
import { Input } from "@/components/ui/input";

export default function ToolPage() {
const [editorState, setEditorState] = useState(EditorState.createEmpty());
const [isClient, setIsClient] = useState(false);
type ToolPageProps = {
note?: Note;
};

useEffect(() => {
setIsClient(true);
}, []);
export default function ToolPage({ note }: ToolPageProps) {
const [editorState, setEditorState] = useState(EditorState.createEmpty());
const [title, setTitle] = useState("");
const [images, setImages] = useState<any>();
const [time, setTime] = useState<Date | undefined>();
const [longitude, setLongitude] = useState<string | undefined>();
const [latitude, setLatitude] = useState<string | undefined>();

useEffect(() => {
// Additional effects as needed
}, [editorState]);
if (note) {
setTitle(note.title);
setImages(note.media);
setTime(note.time);
setLongitude(note.longitude);
setLatitude(note.latitude);

const contentState = stateFromHTML(note.text);
const newEditorState = EditorState.createWithContent(contentState);
setEditorState(newEditorState);
}
}, [note]);

const handleKeyCommand = (command: string) => {
const newState = RichUtils.handleKeyCommand(editorState, command);
Expand Down Expand Up @@ -83,9 +100,19 @@ export default function ToolPage() {
// Implement LinkedIn logo functionality
};

const handleTitleChange = (event: any) => {
setTitle(event.target.value);
};

return (
<div className="flex flex-col h-screen">
{/* Tool icons above the NoteComponent */}
<Input
className="text-3xl font-bold custom-input"
value={title}
onChange={handleTitleChange}
placeholder="Title"
/>

<div className="flex items-center justify-start p-4 bg-gray-200">
<Button
onClick={toggleBold}
Expand Down Expand Up @@ -165,24 +192,21 @@ export default function ToolPage() {
<LinkedInLogoIcon />
</Button>
</div>

{/* Main content area with NoteComponent */}
<main className="flex-grow p-6 lg:p-24">
<div className="max-w-4xl">
{isClient && (
<div className="mt-2 border border-black p-4 rounded-lg w-full bg-white">
<Editor
editorState={editorState}
onChange={setEditorState}
handleKeyCommand={handleKeyCommand}
editorKey="editor"
placeholder="Start writing your notes here . . ."
spellCheck={true}
ariaLabel="Text editor"
ariaMultiline={true}
/>
</div>
)}
<div className="mt-2 border border-black p-4 rounded-lg w-full bg-white">
<Editor
editorState={editorState}
onChange={setEditorState}
handleKeyCommand={handleKeyCommand}
editorKey="editor"
placeholder="Start writing your notes here . . ."
spellCheck={true}
ariaLabel="Text editor"
data-testid="editor"
ariaMultiline={true}
/>
</div>
</div>
</main>
</div>
Expand All @@ -198,7 +222,3 @@ const editorStyles = {
color: "black",
backgroundColor: "white",
};




41 changes: 41 additions & 0 deletions app/lib/components/note_listview 2.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// note_listview.tsx
import React, { useState, useEffect } from 'react';
import { User } from "../models/user_class";
import ApiService from '../utils/api_service';
import { Note } from '../../types';

const NoteListView: React.FC = () => {
const [notes, setNotes] = useState<Note[]>([]);

useEffect(() => {
const fetchNotes = async () => {
const user = User.getInstance();
const userId = await user.getId();
if (userId) {
try {
const userNotes = await ApiService.fetchMessages(false, false, userId);
setNotes(userNotes);
} catch (error) {
console.error('Error fetching notes:', error);
// Handle the error as appropriate for your application
}
}
};

fetchNotes();
}, []);

return (
<div className="my-4">
{notes.map((note) => (
<div key={note.id} className="mb-2 p-2 bg-white rounded shadow">
<h3 className="text-lg font-semibold">{note.title}</h3>
<p>{note.text}</p>
{/* Render other note properties as needed */}
</div>
))}
</div>
);
};

export default NoteListView;
57 changes: 41 additions & 16 deletions app/lib/components/note_listview.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,64 @@
// note_listview.tsx
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect } from "react";
import { User } from "../models/user_class";
import ApiService from '../utils/api_service';
import { Note } from '../../types';
import ApiService from "../utils/api_service";
import { Note } from "../../types";
import { Button } from "@/components/ui/button";
import DataConversion from "../utils/data_conversion";

const NoteListView: React.FC = () => {
type NoteListViewProps = {
onNoteSelect: (note: Note) => void;
};

const NoteListView: React.FC<NoteListViewProps> = ({ onNoteSelect }) => {
const [notes, setNotes] = useState<Note[]>([]);
const [fresh, setFresh] = useState(true);

useEffect(() => {
if (notes.length > 0 && fresh) {
onNoteSelect(notes[0]);
setFresh(false);
}
}, [notes, onNoteSelect]);

useEffect(() => {
const fetchNotes = async () => {
const user = User.getInstance();
const userId = await user.getId();
if (userId) {
try {
const userNotes = await ApiService.fetchMessages(false, false, userId);
setNotes(userNotes);
const userNotes = await ApiService.fetchMessages(
false,
false,
userId
);
setNotes(DataConversion.convertMediaTypes(userNotes).reverse());
} catch (error) {
console.error('Error fetching notes:', error);
// Handle the error as appropriate for your application
console.error("Error fetching notes:", error);
}
}
};

fetchNotes();
}, []);

const handleLoadText = (note: Note) => {
onNoteSelect(note);
};

return (
<div className="my-4">
{notes.map((note) => (
<div key={note.id} className="mb-2 p-2 bg-white rounded shadow">
<h3 className="text-lg font-semibold">{note.title}</h3>
<p>{note.text}</p>
{/* Render other note properties as needed */}
</div>
))}
<div className="my-4 flex flex-col">
{notes.map((note) => {
return (
<Button
key={note.id}
className="bg-secondary text-primary p-2 m-1"
onClick={() => handleLoadText(note)}
>
<h3 className="text-lg font-semibold">{note.title}</h3>
</Button>
);
})}
</div>
);
};
Expand Down
2 changes: 1 addition & 1 deletion app/lib/components/search_bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const SearchBar = () => {
};

return (
<div className="flex items-center w-full min-w-max">
<div className="flex items-center w-min min-w-max">
<Input
type="text"
placeholder="Search..."
Expand Down
16 changes: 10 additions & 6 deletions app/lib/components/side_bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,24 @@ import Link from "next/link";
import { useRouter } from "next/router";
import { User } from "../models/user_class";
import { Button } from "@/components/ui/button";
import SearchBar from "./search_bar";
import NoteListView from "./note_listview";
import { Note } from "@/app/types";

interface SidebarProps {
setNoteComponentVisible: React.Dispatch<React.SetStateAction<boolean>>;
}
type SidebarProps = {
onNoteSelect: (note: Note) => void;
};

const user = User.getInstance();

const Sidebar = () => {
// Wrap the content in a flex container
const Sidebar: React.FC<SidebarProps> = ({ onNoteSelect }) => {
return (
<div className="absolute top-0 left-0 h-screen w-64 bg-gray-200 p-4 overflow-y-auto flex flex-col">
<div className="w-full">
<SearchBar />
</div>
<div>
<NoteListView />{" "}
<NoteListView onNoteSelect={onNoteSelect} />
</div>
<Button data-testid="add-note-button">Add Note</Button>
</div>
Expand Down
Loading
Loading