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

Feature/setup fixes and frontend improvements #10

Merged
merged 5 commits into from
Aug 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
BACKEND_CONTAINER_NAME=python_backend

.PHONY: docker/start docker/start-build docker/clean backend/test backend/migrate backend/upgrade
.PHONY: docker/start docker/start-build docker/clean backend/test backend/migrate backend/upgrade backend/init

# Docker commands:

Expand All @@ -15,6 +15,9 @@ docker/clean:

# Backend commands:

backend/init:
docker compose exec $(BACKEND_CONTAINER_NAME) python3 -m flask --app main db init

backend/migrate:
@if [ "$(message)" = "" ]; then \
echo "Please provide a migration message. Usage: make migrate message='Your migration message'"; \
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ Frontend Application (React): Provides a user-friendly interface for browsing an

2. To start the services run `make docker/start`

3. After starting the services, run the following make commands to setup the database and schemas: `backend/init`, `backend/migration`, `backend/upgrade`

### Makefile Commands

This Makefile provides convenient targets to automate common development tasks.
Expand All @@ -47,6 +49,8 @@ This Makefile provides convenient targets to automate common development tasks.

- **docker/clean**: Remove volumes and delete all images associated with the containers defined in the `docker-compose.yml` file.

- **backend/init**: Inits Flask migration folder.

- **backend/migrate**: Runs Flask migration with a specified message.

- **backend/upgrade**: Upgrades the database schema using Flask.
Expand Down
4 changes: 2 additions & 2 deletions backend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ var/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
Expand Down Expand Up @@ -90,4 +89,5 @@ ENV/
# Rope project settings
.ropeproject

*.code-workspace
*.code-workspace
migrations/
5 changes: 2 additions & 3 deletions frontend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ FROM node:20
# Set the working directory in the container
WORKDIR /frontend


# Copy the current directory contents into the container at /app
COPY . /frontend

Expand All @@ -12,6 +13,4 @@ RUN npm install

EXPOSE 3000

# Command to run the Python script

CMD ["npm", "start"]
CMD ["npm", "run", "start"]
32 changes: 31 additions & 1 deletion frontend/package-lock.json

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

4 changes: 2 additions & 2 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"react-dom": "^18.3.1",
"react-hook-form": "^7.51.5",
"react-router-dom": "^6.23.1",
"react-scripts": "5.0.1",
"react-scripts": "^5.0.1",
"swr": "^2.2.5",
"typescript": "^4.9.5",
"web-vitals": "^2.1.4",
"yup": "^1.4.0"
Expand All @@ -27,7 +28,6 @@
"test": "react-scripts test",
"eject": "react-scripts eject",
"lint": "eslint --fix --ext .ts,.tsx ."

},
"browserslist": {
"production": [
Expand Down
63 changes: 0 additions & 63 deletions frontend/src/components/AuthorForm.tsx

This file was deleted.

28 changes: 6 additions & 22 deletions frontend/src/components/Hooks/UseFilterHook.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,17 @@
import { ChangeEvent, useState } from "react";
import { useState } from "react";

export const useFilterHook = () => {
const [filter, setFilter] = useState<string | null>(null);

const handleChangeFilter = (e: ChangeEvent<HTMLInputElement>): void => {
setFilter(e.target.value);
};

const shouldFilterInWith = (...properties: (unknown | undefined)[]): boolean => {
const isFilterFoundInProperties = (...properties: (unknown | undefined)[]): boolean => {
if (!filter) return true;

let anyPropertyMatch = false;

for (const property of properties) {
if (typeof property === "undefined") {
continue;
}

if (String(property).toLowerCase().includes(filter.toLowerCase())) {
anyPropertyMatch = true;
break;
}
}

return anyPropertyMatch;
return properties.some((property) => property && String(property).toLowerCase().includes(filter.toLowerCase()));
};

return {
handleChangeFilter,
shouldFilterInWith,
filter,
setFilter,
isFilterFoundInProperties,
};
};
95 changes: 49 additions & 46 deletions frontend/src/pages/Authors/Authors.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
import React, { useEffect, useState } from "react";
import React, { useMemo } from "react";
import ManagementService from "services/managementService";
import { useFilterHook } from "components/Hooks/UseFilterHook";
import { Author } from "types/author";
import useSWR from "swr";

const managementService = new ManagementService();

const Authors: React.FC = () => {
const [authors, setAuthors] = useState<Author[]>([]);
const { handleChangeFilter, shouldFilterInWith } = useFilterHook();
const { filter, setFilter, isFilterFoundInProperties } = useFilterHook();
const { data: authorsData, isLoading } = useSWR("authors", () => managementService.getAuthors());

useEffect(() => {
loadAuthors();
}, []);
const filteredAuthors = useMemo(() => {
if (!filter) return authorsData;

const loadAuthors = async () => {
const authors = await managementService.getAuthors();

setAuthors(authors);
};
return authorsData?.filter(({ name, nationality, birthDate, email, id }: Author) =>
isFilterFoundInProperties(name, nationality, birthDate, email, id),
);
}, [authorsData, filter]);

return (
<>
Expand Down Expand Up @@ -46,7 +45,7 @@ const Authors: React.FC = () => {
<input
type="text"
id="table-search"
onChange={handleChangeFilter}
onChange={(e) => setFilter(e.target.value)}
className="block py-3 ps-10 text-sm border rounded-lg w-80 focus:ring-blue-500 focus:border-blue-500 "
placeholder="Search for items"
/>
Expand All @@ -60,40 +59,44 @@ const Authors: React.FC = () => {
</div>
<hr />
<div className="block max-h-[78dvh] overflow-y-auto">
<table className="w-full text-sm text-left rtl:text-right text-gray-500">
<thead className="text-xs uppercase ">
<tr>
<th scope="col" className="px-1 py-3">
Author
</th>
<th scope="col" className="px-1 py-3">
Nationality
</th>
<th scope="col" className="px-1 py-3">
Birth date
</th>
<th scope="col" className="px-1 py-3">
E-mail
</th>
</tr>
</thead>
<tbody>
{authors?.length > 0 &&
authors.map(
({ name, nationality, birthDate, email, id }: Author) =>
shouldFilterInWith(name, nationality, birthDate, email, id) && (
<tr key={id} className="border-b hover:bg-gray-50">
<th scope="row" className="px-1 py-4 font-medium text-gray-900 whitespace-nowrap">
{name}
</th>
<td className="px-1 py-4">{nationality}</td>
<td className="px-1 py-4">{birthDate}</td>
<td className="px-1 py-4">{email}</td>
</tr>
),
)}
</tbody>
</table>
{filteredAuthors && filteredAuthors.length > 0 ? (
<table className="w-full text-sm text-left rtl:text-right text-gray-500">
<thead className="text-xs uppercase ">
<tr>
<th scope="col" className="px-1 py-3">
Author
</th>
<th scope="col" className="px-1 py-3">
Nationality
</th>
<th scope="col" className="px-1 py-3">
Birth date
</th>
<th scope="col" className="px-1 py-3">
E-mail
</th>
</tr>
</thead>
<tbody>
{filteredAuthors.map(({ id, name, nationality, birthDate, email }) => (
<>
<tr key={id} className="border-b hover:bg-gray-50">
<th scope="row" className="px-1 py-4 font-medium text-gray-900 whitespace-nowrap">
{name}
</th>
<td className="px-1 py-4">{nationality}</td>
<td className="px-1 py-4">{birthDate}</td>
<td className="px-1 py-4">{email}</td>
</tr>
</>
))}
</tbody>
</table>
) : isLoading ? (
<span>Loading...</span>
) : (
<span className="pt-5">No authors registered</span>
)}
</div>
</>
);
Expand Down
Loading
Loading