Skip to content

Commit

Permalink
feat: species information popup (#29)
Browse files Browse the repository at this point in the history
  • Loading branch information
natesawant authored Nov 6, 2024
1 parent e298a80 commit cf1d61b
Show file tree
Hide file tree
Showing 23 changed files with 667 additions and 97 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files
venv/
scripts/__pycache__/

# dependencies
node_modules/
Expand Down
45 changes: 0 additions & 45 deletions backend/src/__tests__/fish.test.ts

This file was deleted.

68 changes: 68 additions & 0 deletions backend/src/__tests__/species.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
jest.mock('../middlewares/authMiddleware', () => ({
isAuthenticated: (
req: express.Request,
res: express.Response,
next: express.NextFunction,
) => {
return next();
},
}));
import { Species } from '../models/species';
import request from 'supertest';
import express from 'express';
import species from '../routes/species';
import mongoose from 'mongoose';

jest.mock('../models/species');

const app = express();
const router = express.Router();
species(router);

app.use(router);
const speciesMock = Species.findById as jest.Mock;
const speciesFindMock = Species.findOne as jest.Mock;

describe('GET /species/id', () => {
beforeEach(() => {
speciesMock.mockReset();
});

it('No species with this id', async () => {
const randomObjectId = new mongoose.Types.ObjectId().toString();
const query = `/species/${randomObjectId}`;
const res = await request(app).get(query);
expect(res.status).toBe(404);
});

it('Gets a specific species id', async () => {
const id = new mongoose.Types.ObjectId().toString();
const species = { _id: id, scientificName: 'Scorpaena brachion' };
speciesMock.mockResolvedValue(species);
const res = await request(app).get(`/species/id/${id}`);
expect(res.status).toBe(200);
expect(res.body).toEqual(species);
});
});

describe('GET /species/scientific/id', () => {
beforeEach(() => {
speciesFindMock.mockReset();
});

it('No species with this scientific name', async () => {
const query = `/species/scientific/doesntexist"`;
const res = await request(app).get(query);
expect(res.status).toBe(404);
});

it('Gets a specific species by scientific name', async () => {
const id = new mongoose.Types.ObjectId().toString();
const scientificName = 'Scorpaena brachion';
const species = { _id: id, scientificName: scientificName };
speciesFindMock.mockResolvedValue(species);
const res = await request(app).get(`/species/scientific/${scientificName}`);
expect(res.status).toBe(200);
expect(res.body).toEqual(species);
});
});
9 changes: 0 additions & 9 deletions backend/src/controllers/fish/get.ts

This file was deleted.

19 changes: 19 additions & 0 deletions backend/src/controllers/species/get.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import express from 'express';
import { Species } from '../../models/species';

export const getById = async (req: express.Request, res: express.Response) => {
const id = req.params.id;
const species = await Species.findById(id);
if (!species) return res.status(404).json({ message: 'Species not found' });
return res.status(200).json(species);
};

export const getByScientificName = async (
req: express.Request,
res: express.Response,
) => {
const scientificName = req.params.scientificName;
const species = await Species.findOne({ scientificName: scientificName });
if (!species) return res.status(404).json({ message: 'Species not found' });
return res.status(200).json(species);
};
10 changes: 0 additions & 10 deletions backend/src/models/fish.ts

This file was deleted.

13 changes: 13 additions & 0 deletions backend/src/models/species.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import mongoose from 'mongoose';

const SpeciesSchema = new mongoose.Schema({
aphiaId: { type: String, required: true },
articleUrl: { type: String },
articleTitle: { type: String },
commonNames: [String],
scientificName: { type: String },
introduction: { type: String },
imageUrls: [String],
});

export const Species = mongoose.model('Species', SpeciesSchema);
28 changes: 0 additions & 28 deletions backend/src/routes/fish.ts

This file was deleted.

4 changes: 2 additions & 2 deletions backend/src/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import healthcheck from './healthcheck';
import divelog from './divelog';
import swagger from './swagger';
import user from './user';
import fish from './fish';
import species from './species';

const router = express.Router();
export default (): express.Router => {
authentification(router);
healthcheck(router);
divelog(router);
user(router);
fish(router);
species(router);
swagger(router);
return router;
};
51 changes: 51 additions & 0 deletions backend/src/routes/species.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import express from 'express';
import { isAuthenticated } from '../middlewares/authMiddleware';
import { getById, getByScientificName } from '../controllers/species/get';

/**
* @swagger
* /species/id/{id}:
* get:
* summary: Get species by ID
* description: Retrieve a species by its unique ID.
* parameters:
* - in: path
* name: id
* required: true
* description: ID of the species to retrieve
* schema:
* type: string
* responses:
* 200:
* description: Successfully retrieved species
* 401:
* description: Unauthorized
* 404:
* description: species not found
* /species/scientifc/{scientificName}:
* get:
* summary: Get species by scientificName
* description: Retrieve a species by its unique scientificName.
* parameters:
* - in: path
* name: scientificName
* required: true
* description: scientificName of the species to retrieve
* schema:
* type: string
* responses:
* 200:
* description: Successfully retrieved species
* 401:
* description: Unauthorized
* 404:
* description: species not found
*/
export default (router: express.Router) => {
router.get('/species/id/:id', isAuthenticated, getById);
router.get(
'/species/scientific/:scientificName',
isAuthenticated,
getByScientificName,
);
};
12 changes: 11 additions & 1 deletion frontend/app/(app)/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import { View, Text } from 'react-native';
import Button from '../../components/button';
import { useAuthStore } from '../../auth/authStore';
import Badge from '../../assets/fish badge.svg';
import InfoPopup from '../../components/info-popup';
import PopulatedInfoPopupButton from '../../components/populated-info-popup';

const Home = () => {
const { logout, loading, error: authError, isAuthenticated } = useAuthStore();
const { logout, loading, error: authError } = useAuthStore();

return (
<View className="flex-1 justify-center items-center">
Expand All @@ -20,6 +22,14 @@ const Home = () => {
textOnly
text={loading ? 'Logging out' : 'Logout'}
/>
<View className=" flex flex-col">
<PopulatedInfoPopupButton speciesId="Canthidermis maculata" />
<PopulatedInfoPopupButton speciesId="Sufflamen bursa" />
<PopulatedInfoPopupButton speciesId="Gaidropsarus mediterraneus" />
<PopulatedInfoPopupButton speciesId="Gaidropsarus vulgaris" />
<PopulatedInfoPopupButton speciesId="Spicara smaris" />
</View>
<InfoPopup />
</View>
);
};
Expand Down
7 changes: 5 additions & 2 deletions frontend/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { AuthProvider, useAuth } from '../auth/authProvider';
import { useEffect } from 'react';
import { useAuthStore } from '../auth/authStore';
import { NavBar } from './(app)/(components)/navbar';
import { InfoPopupProvider } from '../contexts/info-popup-context';

const queryClient = new QueryClient();

Expand Down Expand Up @@ -48,8 +49,10 @@ const RootLayout = () => {
return (
<QueryClientProvider client={queryClient}>
<AuthProvider>
<StatusBar />
<InitialLayout />
<InfoPopupProvider>
<StatusBar />
<InitialLayout />
</InfoPopupProvider>
</AuthProvider>
</QueryClientProvider>
);
Expand Down
Loading

0 comments on commit cf1d61b

Please sign in to comment.