Skip to content

Commit

Permalink
Merge pull request #56 from oss-slu/53-render-the-notes-searched-on-t…
Browse files Browse the repository at this point in the history
…he-searchbar

53 render the notes searched on the searchbar
  • Loading branch information
yashb196 authored Dec 5, 2023
2 parents 2d78f24 + 70c0cc0 commit 576795b
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 130 deletions.
76 changes: 37 additions & 39 deletions app/__tests__/search_bar.test.tsx
Original file line number Diff line number Diff line change
@@ -1,68 +1,66 @@
import React from 'react';
import SearchBar from '../lib/components/search_bar'; // Make sure to adjust the import path
import "@testing-library/jest-dom";
import { render, fireEvent } from '@testing-library/react';

describe('SearchBar Component', () => {
let originalConsoleError: jest.Mock;
let mockOnSearch: jest.Mock;

test('renders the SearchBar component', () => {
render(<SearchBar />);
});
;
beforeEach(() => {
// Mock console.error
originalConsoleError = console.error;
console.error = jest.fn();

// Create a mock function for onSearch
mockOnSearch = jest.fn();
});

afterEach(() => {
// Restore original console.error
console.error = originalConsoleError;
});

test('renders the SearchBar component', () => {
render(<SearchBar onSearch={mockOnSearch} />);
});

test('updates the search input when the user types', () => {
const { getByPlaceholderText } = render(<SearchBar />);
test('updates the search input when the user types', () => {
const { getByPlaceholderText } = render(<SearchBar onSearch={mockOnSearch} />);
const searchInput = getByPlaceholderText('Search...'); // Assuming 'Search...' is the placeholder text

// Simulate user input

fireEvent.change(searchInput, { target: { value: 'Sample Query' } });

// Check if the search input value updates correctly
expect(searchInput).toHaveValue('Sample Query');
expect(mockOnSearch).toHaveBeenCalledWith('Sample Query');
});

test('triggers search on pressing Enter key', () => {
const { getByPlaceholderText, getByTestId, queryByText } = render(<SearchBar />);
const { getByPlaceholderText } = render(<SearchBar onSearch={mockOnSearch} />);
const searchInput = getByPlaceholderText('Search...'); // Assuming 'Search...' is the placeholder text
const searchButton = getByTestId('search-button'); // Use your custom Test ID here

// Enter a search query

fireEvent.change(searchInput, { target: { value: 'Sample Query' } });

// Press the Enter key
fireEvent.keyPress(searchInput, { key: 'Enter', code: 'Enter', charCode: 13 });

expect(mockOnSearch).toHaveBeenCalledWith('Sample Query');
});

test('handles large amount of search input', () => {
const { getByPlaceholderText, getByTestId, queryByText } = render(<SearchBar />);
const { getByPlaceholderText } = render(<SearchBar onSearch={mockOnSearch} />);
const searchInput = getByPlaceholderText('Search...'); // Assuming 'Search...' is the placeholder text
const searchButton = getByTestId('search-button'); // Use your custom Test ID here

// Enter a large amount of text in the search input
const largeText = 'Lorem ipsum '.repeat(1000); // Creating a large text

fireEvent.change(searchInput, { target: { value: largeText } });

// Press the Enter key
fireEvent.keyPress(searchInput, { key: 'Enter', code: 'Enter', charCode: 13 });

// Check if the search is aborted or if the component handles it gracefully
// You can check if there are any performance issues
expect(queryByText('Sample Query')).not.toBeInTheDocument();
expect(mockOnSearch).toHaveBeenCalledWith(largeText);
});

test('handles search input with special characters', () => {
const { getByPlaceholderText, getByTestId, queryByText } = render(<SearchBar />);
const { getByPlaceholderText } = render(<SearchBar onSearch={mockOnSearch} />);
const searchInput = getByPlaceholderText('Search...'); // Assuming 'Search...' is the placeholder text
const searchButton = getByTestId('search-button'); // Use your custom Test ID here

// Enter a search query with special characters
const specialCharacters = '!@#$%^&*()';

fireEvent.change(searchInput, { target: { value: specialCharacters } });

// Press the Enter key
fireEvent.keyPress(searchInput, { key: 'Enter', code: 'Enter', charCode: 13 });

// Check if the search is handled correctly or if any special characters are sanitized
expect(queryByText('Sample Query')).not.toBeInTheDocument();
});
expect(mockOnSearch).toHaveBeenCalledWith(specialCharacters);
});

});
22 changes: 19 additions & 3 deletions app/__tests__/sidebar.test.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,37 @@
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import { render, screen } from '@testing-library/react';
import { useRouter } from 'next/router';
import Sidebar from '../lib/components/side_bar'; // Update the path to your Sidebar component accordingly
import moxios from 'moxios';

jest.mock('next/router', () => ({
useRouter: jest.fn(),
}));

describe('Sidebar Component', () => {
let mockPush: jest.Mock;
let originalConsoleError: jest.Mock;

beforeEach(() => {
// Install Moxios before each test
moxios.install();

mockPush = jest.fn();
(useRouter as jest.Mock).mockImplementation(() => ({
push: mockPush,
}));

// Mock console.error
originalConsoleError = console.error;
console.error = jest.fn();
});

afterEach(() => {
// Uninstall Moxios after each test
moxios.uninstall();

// Restore original console.error
console.error = originalConsoleError;
});

it('renders the sidebar correctly', () => {
Expand All @@ -34,7 +51,6 @@ describe('Sidebar Component', () => {
expect(linkElement).toBeInTheDocument();
});



// ... any other tests ...

});
41 changes: 0 additions & 41 deletions app/lib/components/note_listview 2.tsx

This file was deleted.

26 changes: 3 additions & 23 deletions app/lib/components/note_listview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,41 +7,21 @@ import { Button } from "@/components/ui/button";
import DataConversion from "../utils/data_conversion";

type NoteListViewProps = {
notes: Note[];
onNoteSelect: (note: Note) => void;
};

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

useEffect(() => {
if (notes.length > 0 && fresh) {
onNoteSelect(notes[0]);
setFresh(false);
console.log("NoteListView: useEffect: onNoteSelect", notes[0])
}
}, [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(DataConversion.convertMediaTypes(userNotes).reverse());
} catch (error) {
console.error("Error fetching notes:", error);
}
}
};

fetchNotes();
}, []);

const handleLoadText = (note: Note) => {
onNoteSelect(note);
};
Expand Down
32 changes: 12 additions & 20 deletions app/lib/components/search_bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,17 @@ import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { MagnifyingGlassIcon } from "@radix-ui/react-icons";

const SearchBar = () => {
type SearchBarProps = {
onSearch: (query: string) => void;
};

const SearchBar: React.FC<SearchBarProps> = ({ onSearch }) => {
const [searchText, setSearchText] = useState("");

const handleSearch = async () => {
console.log("Search text:", searchText);
if (!searchText) {
console.log("Search text is empty. Aborting search.");
return;
}
try {
const response = await ApiService.searchMessages(searchText);
console.log("API Response:", response);
} catch (error) {
console.error("API Error:", error);
}
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const query = e.target.value;
setSearchText(query);
onSearch(query);
};

return (
Expand All @@ -29,14 +25,10 @@ const SearchBar = () => {
placeholder="Search..."
className="border border-gray-300 rounded-md p-2 flex-grow"
value={searchText}
onChange={(e) => setSearchText(e.target.value)}
onChange={handleInputChange}
/>
<Button
className="px-4 py-2 rounded-md"
onClick={handleSearch}
data-testid="search-button"
>
<MagnifyingGlassIcon className="w-6 h-6" />
<Button className="px-4 py-2 rounded-md" data-testid="search-button">
<MagnifyingGlassIcon className="w-6 h-6" />
</Button>
</div>
);
Expand Down
45 changes: 41 additions & 4 deletions app/lib/components/side_bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,63 @@ import { Button } from "@/components/ui/button";
import SearchBar from "./search_bar";
import NoteListView from "./note_listview";
import { Note } from "@/app/types";
import ApiService from "../utils/api_service";

type SidebarProps = {
onNoteSelect: (note: Note) => void;
};

const user = User.getInstance();
const userId = user.getId();


const Sidebar: React.FC<SidebarProps> = ({ onNoteSelect }) => {
const [notes, setNotes] = useState<Note[]>([]);
const [filteredNotes, setFilteredNotes] = useState<Note[]>([]);

useEffect(() => {
const fetchUserMessages = async () => {
try {
const userId = await user.getId();
if (userId) {
const userNotes = await ApiService.fetchUserMessages(userId);
setNotes(userNotes);
setFilteredNotes(userNotes);
} else {
console.error("User not logged in");
}
} catch (error) {
console.error("Error fetching user messages:", error);
}
};

fetchUserMessages();
}, []);

const handleSearch = (searchQuery: string) => {
if (!searchQuery.trim()) {
setFilteredNotes(notes);
return;
}
const filtered = notes.filter(note =>
note.title.toLowerCase().includes(searchQuery.toLowerCase())
);
setFilteredNotes(filtered);
};

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 className="w-full">
<SearchBar onSearch={handleSearch} />
</div>
<div>
<NoteListView onNoteSelect={onNoteSelect} />
<NoteListView notes={filteredNotes} onNoteSelect={onNoteSelect} />
</div>
<Button data-testid="add-note-button">Add Note</Button>
</div>
);
}
};


export default Sidebar;

33 changes: 33 additions & 0 deletions app/lib/utils/api_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,5 +174,38 @@ export default class ApiService {
}
}

/**
* Fetches all messages for a specific user.
* @param {string} userId - The ID of the user whose messages are to be fetched.
* @returns {Promise<any[]>} - The array of messages fetched from the API.
*/
static async fetchUserMessages(userId: string): Promise<any[]> {
try {
const url = "http://lived-religion-dev.rerum.io/deer-lr/query";
const headers = {
"Content-Type": "application/json",
};

// Body for the request: fetch messages of type 'message' created by the specified user
const body = {
type: "message",
creator: userId
};

const response = await fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
});

const data = await response.json();
return data;
} catch (error) {
console.error("Error fetching user messages:", error);
throw error;
}
}



}

0 comments on commit 576795b

Please sign in to comment.