Skip to content

Commit

Permalink
Merge pull request #20 from MagnunAVF/feat/dashboard
Browse files Browse the repository at this point in the history
feat: dashboard
  • Loading branch information
MagnunAVF authored Sep 20, 2024
2 parents e4f76bc + 16ca991 commit d3e2095
Show file tree
Hide file tree
Showing 10 changed files with 266 additions and 96 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@

- There are system requirements? Yes, check [Specification](./docs/Specification.md)
- How to run in localhost? Check [localhost guide](./envs/localhost/README.md)
- What are the api routes? Check [Api Routes](./docs/api-routes.md)
- How to deploy the application? Check [deploy guide](./envs/hml/README.md)
- There are possible improvementes? Yes, check [Backlog](./docs/Backlog.md)
220 changes: 124 additions & 96 deletions api/postman/demeter-api.postman_collection.json
Original file line number Diff line number Diff line change
@@ -1,97 +1,125 @@
{
"info": {
"_postman_id": "48895354-872d-4ddd-b78a-7bd15ce12326",
"name": "demeter-api",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
"_exporter_id": "1451659"
},
"item": [
{
"name": "Create Invalid Farmer",
"request": {
"method": "POST",
"header": [],
"body": {
"mode": "raw",
"raw": "{\n \"name\": \"Maximus\",\n \"farm\": {\n \"name\": \"My farm\",\n \"city\": \"Cerro Largo\",\n \"state\": \"RS\",\n \"totalArea\": 100,\n \"arableArea\": 60,\n \"vegetationArea\": 40,\n \"crops\": [\"Soy\", \"Bean\"]\n }\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "{{url}}/farmers/",
"host": ["{{url}}"],
"path": ["farmers", ""]
}
},
"response": []
},
{
"name": "Update Farmer",
"request": {
"method": "PUT",
"header": [],
"body": {
"mode": "raw",
"raw": "{\n \"name\": \"Maximus\",\n \"document\": \"092.875.200-38\",\n \"farm\": {\n \"name\": \"My Updated farm\",\n \"city\": \"Cerro Largo\",\n \"state\": \"RS\",\n \"totalArea\": 110,\n \"arableArea\": 60,\n \"vegetationArea\": 40,\n \"crops\": [\"Soy\"]\n }\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "{{url}}/farmers/{{document}}",
"host": ["{{url}}"],
"path": ["farmers", "{{document}}"]
}
},
"response": []
},
{
"name": "New Request",
"request": {
"method": "GET",
"header": []
},
"response": []
},
{
"name": "Create Farmer",
"request": {
"method": "POST",
"header": [],
"body": {
"mode": "raw",
"raw": "{\n \"name\": \"Maximus\",\n \"document\": \"092.875.200-38\",\n \"farm\": {\n \"name\": \"My farm\",\n \"city\": \"Cerro Largo\",\n \"state\": \"RS\",\n \"totalArea\": 100,\n \"arableArea\": 60,\n \"vegetationArea\": 40,\n \"crops\": [\"Soy\", \"Bean\"]\n }\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "{{url}}/farmers/",
"host": ["{{url}}"],
"path": ["farmers", ""]
}
},
"response": []
},
{
"name": "Delete Farmer",
"request": {
"method": "DELETE",
"header": [],
"url": {
"raw": "{{url}}/farmers/{{document}}",
"host": ["{{url}}"],
"path": ["farmers", "{{document}}"]
}
},
"response": []
}
]
}
"info": {
"_postman_id": "48895354-872d-4ddd-b78a-7bd15ce12326",
"name": "demeter-api",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
"_exporter_id": "1451659"
},
"item": [
{
"name": "Create Invalid Farmer",
"request": {
"method": "POST",
"header": [],
"body": {
"mode": "raw",
"raw": "{\n \"name\": \"Maximus\",\n \"farm\": {\n \"name\": \"My farm\",\n \"city\": \"Cerro Largo\",\n \"state\": \"RS\",\n \"totalArea\": 100,\n \"arableArea\": 60,\n \"vegetationArea\": 40,\n \"crops\": [\"Soy\", \"Bean\"]\n }\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "{{url}}/farmers/",
"host": [
"{{url}}"
],
"path": [
"farmers",
""
]
}
},
"response": []
},
{
"name": "Update Farmer",
"request": {
"method": "PUT",
"header": [],
"body": {
"mode": "raw",
"raw": "{\n \"name\": \"Maximus\",\n \"document\": \"092.875.200-38\",\n \"farm\": {\n \"name\": \"My Updated farm\",\n \"city\": \"Cerro Largo\",\n \"state\": \"RS\",\n \"totalArea\": 110,\n \"arableArea\": 60,\n \"vegetationArea\": 40,\n \"crops\": [\"Soy\"]\n }\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "{{url}}/farmers/{{document}}",
"host": [
"{{url}}"
],
"path": [
"farmers",
"{{document}}"
]
}
},
"response": []
},
{
"name": "Create Farmer",
"request": {
"method": "POST",
"header": [],
"body": {
"mode": "raw",
"raw": "{\n \"name\": \"Maximus\",\n \"document\": \"092.875.200-38\",\n \"farm\": {\n \"name\": \"My farm\",\n \"city\": \"Cerro Largo\",\n \"state\": \"RS\",\n \"totalArea\": 100,\n \"arableArea\": 60,\n \"vegetationArea\": 40,\n \"crops\": [\"Soy\", \"Bean\"]\n }\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "{{url}}/farmers",
"host": [
"{{url}}"
],
"path": [
"farmers"
]
}
},
"response": []
},
{
"name": "Delete Farmer",
"request": {
"method": "DELETE",
"header": [],
"url": {
"raw": "{{url}}/farmers/{{document}}",
"host": [
"{{url}}"
],
"path": [
"farmers",
"{{document}}"
]
}
},
"response": []
},
{
"name": "Dashboard Data",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{url}}/dashboard",
"host": [
"{{url}}"
],
"path": [
"dashboard"
]
}
},
"response": []
}
]
}
6 changes: 6 additions & 0 deletions api/src/core/repository/DashboardRepository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
interface DashboardRepository {
getFarmsTotalNumber(): Promise<number>
getFarmsTotalArea(): Promise<number>
}

export default DashboardRepository
23 changes: 23 additions & 0 deletions api/src/core/useCases/Dashboard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import DashboardRepository from '../repository/DashboardRepository'
import UseCase from './UseCase'

export type DashboardArea = {
totalFarms: number
totalArea: number
}

class Dashboard implements UseCase<void, DashboardArea> {
constructor(private dashboardRepository: DashboardRepository) {}

async execute(): Promise<DashboardArea> {
const totalFarms = await this.dashboardRepository.getFarmsTotalNumber()
const totalArea = await this.dashboardRepository.getFarmsTotalArea()

return {
totalArea,
totalFarms,
}
}
}

export default Dashboard
22 changes: 22 additions & 0 deletions api/src/external/api/DashboardController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Express } from 'express'
import Dashboard from '../../core/useCases/Dashboard'
import DashboardDto from './dtos/DashboardDto'

class DashboardController {
constructor(server: Express, useCase: Dashboard) {
server.get('/dashboard', async (req, resp) => {
try {
const dashboardData: DashboardDto = await useCase.execute()

resp.status(200).send(dashboardData)
} catch (error: any) {
console.log(`Error in Dashboard: ${error}`)

resp.status(500).send('Internal Server Error')
}
})
}
}

export default DashboardController
6 changes: 6 additions & 0 deletions api/src/external/api/dtos/DashboardDto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
interface DashboardDto {
totalFarms: number
totalArea: number
}

export default DashboardDto
25 changes: 25 additions & 0 deletions api/src/external/repository/PgDashboardRepository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { PrismaClient } from '@prisma/client'
import DashboardRepository from '../../core/repository/DashboardRepository'

class PgDashboardRepository implements DashboardRepository {
prisma = new PrismaClient()

async getFarmsTotalNumber(): Promise<number> {
const totalFarms = await this.prisma.farm.count()

return totalFarms
}

async getFarmsTotalArea(): Promise<number> {
const sumTotalArea = await this.prisma.farm.aggregate({
_sum: {
totalArea: true,
},
})
const data = sumTotalArea['_sum']['totalArea']

return data
}
}

export default PgDashboardRepository
6 changes: 6 additions & 0 deletions api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import DeleteFarmerController from './external/api/DeleteFarmerController'
import EditFarmer from './core/useCases/EditFarmer'
import CreateFarmer from './core/useCases/CreateFarmer'
import DeleteFarmer from './core/useCases/DeleteFarmer'
import Dashboard from './core/useCases/Dashboard'
import PgDashboardRepository from './external/repository/PgDashboardRepository'
import DashboardController from './external/api/DashboardController'

const app = express()
const PORT = 3000
Expand All @@ -23,6 +26,7 @@ app.get('/', async (req, res) => {
const idGenerator = new Uuid()
const documentValidator = new CpfAndCnpjValidator()
const farmerRepository = new PgFarmerRepository(documentValidator)
const dashboardRepository = new PgDashboardRepository()

// use cases
const createFarmer = new CreateFarmer(
Expand All @@ -32,11 +36,13 @@ const createFarmer = new CreateFarmer(
)
const updateFarmer = new EditFarmer(farmerRepository, documentValidator)
const deleteFarmer = new DeleteFarmer(farmerRepository)
const dashboard = new Dashboard(dashboardRepository)

// routes and controllers
new CreateFarmerController(app, createFarmer)
new UpdateFarmerController(app, updateFarmer)
new DeleteFarmerController(app, deleteFarmer)
new DashboardController(app, dashboard)

app.listen(PORT, () => {
console.log(`Running in http://localhost:${PORT}!`)
Expand Down
Loading

0 comments on commit d3e2095

Please sign in to comment.