diff --git a/src/components/inscribete/FindVoterCenter/findYourCenterMachine.tsx b/src/components/inscribete/FindVoterCenter/findYourCenterMachine.tsx index c882dcf5..3f65cfd5 100644 --- a/src/components/inscribete/FindVoterCenter/findYourCenterMachine.tsx +++ b/src/components/inscribete/FindVoterCenter/findYourCenterMachine.tsx @@ -1,17 +1,13 @@ import { createMachine, assign } from "xstate" + import { FindYourCenterContext, FindYourCenterEvent } from "./types" +import { VoterInformationResource } from "../../../packages/practica/resource" const isNumberExpr = new RegExp(/^\d+$/) -const getVoterDetails = (voterId?: string) => - fetch(`https://api.paravotar.org/consulta?voterId=${voterId}`).then( - response => { - if (!response.ok) { - throw new Error("HTTP status code: " + response.status) - } - return response.json() - } - ) +const getVoterDetails = (voterId?: string) => { + return VoterInformationResource.getVoterInfo(voterId) +} export const findYourCenterMachine = createMachine< FindYourCenterContext, diff --git a/src/packages/generate-ballot/machines/ballot-machine.ts b/src/packages/generate-ballot/machines/ballot-machine.ts index bad7eb28..ab20b62d 100644 --- a/src/packages/generate-ballot/machines/ballot-machine.ts +++ b/src/packages/generate-ballot/machines/ballot-machine.ts @@ -1,17 +1,17 @@ import { Machine, assign } from "xstate" + +import { BallotResource } from "../../practica/resource" import { LegislativeBallotConfig, MunicipalBallotConfig, StateBallotConfig, } from "../../practica/services/ballot-configs" -import { CDN_URL } from "../../practica/services/constants" import { BallotMachineContext } from "../types/ballot-machine" async function fetchBallot(path: string | null) { if (path) { - const resp = await fetch(`${CDN_URL}${path}/data.json`) - const data = await resp.json() + const data = await BallotResource.getBallot(`${path}/`) return data } diff --git a/src/packages/practica/resource.ts b/src/packages/practica/resource.ts new file mode 100644 index 00000000..b0f66f88 --- /dev/null +++ b/src/packages/practica/resource.ts @@ -0,0 +1,35 @@ +import api from "../../services/api" +import { BallotsResponse, OcrResult, VoterInfo } from "./services/types" +import { CDN_URL } from "./services/constants" + +export const VoterInformationResource = { + getVoterInfo(voterId?: string) { + return api.get(`/consulta?voterId=${voterId}`) + }, +} + +export const BallotResource = { + getBallotsByPrecint(precint: string) { + return api.get(`/ballots/ByPrecint?precintId=${precint}`) + }, + + getBallotsByTown(town: string) { + return api.get(`/ballots/ByTown?townId=${town}`) + }, + + async getBallot(path: string) { + return api.get(`/${path}data.json`, { baseUrl: CDN_URL }) + }, + + createBallotPdf(ballot: { + ballotType: string + ballotPath: string + votes: string + }) { + return api.post("/createBallotTask", ballot) + }, + + getBallotPdf(params: string) { + api.get(`/getPdfUrl?${params}`) + }, +} diff --git a/src/packages/practica/services/ballot-finder-service.ts b/src/packages/practica/services/ballot-finder-service.ts index dc261f6a..67cc7952 100644 --- a/src/packages/practica/services/ballot-finder-service.ts +++ b/src/packages/practica/services/ballot-finder-service.ts @@ -1,74 +1,17 @@ -import { API_URL } from "./constants" - -type VoterInfo = { - estatus: string - numeroElectoral: string - precinto: string - unidad: string -} - -type BallotsResponse = { - estatal: string - municipal: string - legislative: string -} +import { BallotResource, VoterInformationResource } from "../resource" +import { BallotsResponse, VoterInfo } from "./types" async function getBallotsByVoterId(voterId: string) { - const voterInfoRes = await fetch(`${API_URL}/consulta?voterId=${voterId}`) - const voterInfoJson: VoterInfo = await voterInfoRes.json() - const ballotsRes = await fetch( - `${API_URL}/ballots/ByPrecint?precintId=${voterInfoJson.precinto}` + const voterInfo: VoterInfo = await VoterInformationResource.getVoterInfo( + voterId + ) + const ballots: BallotsResponse = await BallotResource.getBallotsByPrecint( + voterInfo.precinto ) - const ballotsJson: BallotsResponse = await ballotsRes.json() - return ballotsJson + return ballots } -// // Prefetch ballot data -// const ballots = Object.entries(ballotsJson).map(async ([key, value]) => { -// try { -// const ballotRes = await fetch(`${PUBLIC_S3_BUCKET}/${value}data.json`) -// const ballotJson: OcrResult[][] = await ballotRes.json() - -// if (key === "estatal") { -// return { -// [key]: new StateBallotConfig(ballotJson, ballotsJson.estatal), -// } -// } else if (key === "municipal") { -// return { -// [key]: new MunicipalBallotConfig(ballotJson, ballotsJson.municipal), -// } -// } else { -// return { -// [key]: new LegislativeBallotConfig( -// ballotJson, -// ballotsJson.legislativa -// ), -// } -// } -// } catch (err) { -// console.log(err) -// } -// }) - -// const allBallotsJson = await Promise.all(ballots) -// const initialValue: { -// estatal?: StateBallotConfig -// municipal?: MunicipalBallotConfig -// legislativa?: LegislativeBallotConfig -// } = { -// estatal: undefined, -// municipal: undefined, -// legislativa: undefined, -// } - -// return allBallotsJson.reduce((prev, curr) => { -// return { -// ...prev, -// ...curr, -// } -// }, initialValue) - function prefixPrecint(precint: string) { let input = precint const inputSize = precint.length @@ -89,21 +32,17 @@ function prefixPrecint(precint: string) { async function getBallotsByPrecint(precint: string) { const prefixedPrecint = prefixPrecint(precint) - const ballotsByPrecintRes = await fetch( - `${API_URL}/ballots/ByPrecint?precintId=${prefixedPrecint}` + const ballots: BallotsResponse = await BallotResource.getBallotsByPrecint( + prefixedPrecint ) - const ballotsJson: BallotsResponse = await ballotsByPrecintRes.json() - return ballotsJson + return ballots } async function getBallotsByTown(town: string) { - const ballotsByPrecintRes = await fetch( - `${API_URL}/ballots/ByTown?townId=${town}` - ) - const ballotsJson: BallotsResponse = await ballotsByPrecintRes.json() + const ballots: BallotsResponse = await BallotResource.getBallotsByTown(town) - return ballotsJson + return ballots } export enum FindByType { diff --git a/src/packages/practica/services/ballot-service.ts b/src/packages/practica/services/ballot-service.ts index b34fc520..4a1dfe51 100644 --- a/src/packages/practica/services/ballot-service.ts +++ b/src/packages/practica/services/ballot-service.ts @@ -1,6 +1,14 @@ import { stringify } from "qs" + import { BallotType, Selection } from "../../../ballot-validator/types" import { VotesCoordinates } from "../../generate-ballot/types/ballot-machine" +import { + CandidateVoteStrategy, + MixedVoteStrategy, + PartyVoteStrategy, + VoteUpdateManager, +} from "../strategies" +import { BallotResource } from "../resource" import { BallotConfigs, LegislativeBallotConfig, @@ -8,16 +16,9 @@ import { StateBallotConfig, } from "./ballot-configs" import { ElectiveField } from "./ballot-configs/base" -import { API_URL, CDN_URL } from "./constants" import { OcrResult, PracticeContext } from "./types" import { getExplicitlySelectedVotes, Vote } from "./vote-service" import BallotFinder, { FindByType } from "./ballot-finder-service" -import { - CandidateVoteStrategy, - MixedVoteStrategy, - PartyVoteStrategy, - VoteUpdateManager, -} from "../strategies" type FindByEventParams = { userInput: string @@ -65,8 +66,7 @@ const BallotService = { legislativa: LegislativeBallotConfig }> = Object.entries(ballotPaths).map(async ([key, value]) => { try { - const ballotRes = await fetch(`${CDN_URL}/${value}data.json`) - const ballotJson: OcrResult[][] = await ballotRes.json() + const ballotJson: OcrResult[][] = await BallotResource.getBallot(value) if (key === "estatal") { return { @@ -195,42 +195,19 @@ const BallotService = { } } ) - const votes = JSON.stringify(voteCoordinates) - - const res = await fetch(`${API_URL}/createBallotTask`, { - method: "POST", - body: JSON.stringify({ - ballotType: event.ballotType, - ballotPath: `/${event.ballotPath.substr( - 0, - event.ballotPath.length - 1 - )}`, - votes: votes, - }), - }) - const result = await res.json() - - const params = new URLSearchParams({ + const result = await BallotResource.createBallotPdf({ ballotType: event.ballotType, ballotPath: `/${event.ballotPath.substr(0, event.ballotPath.length - 1)}`, + votes: JSON.stringify(voteCoordinates), }) - params.append("votes", votes) - params.toString() - return result.uuid }, async getPdfUrl(context: PracticeContext) { const { uuid } = context const params = stringify({ uuid }) - const res = await fetch(`${API_URL}/getPdfUrl?${params}`) - - if (!res.ok) { - throw new Error("Something went wrong") - } - - const result = await res.json() + const result = await BallotResource.getBallotPdf(params) return result }, diff --git a/src/packages/practica/services/types.ts b/src/packages/practica/services/types.ts index bc8a3a49..417bc304 100644 --- a/src/packages/practica/services/types.ts +++ b/src/packages/practica/services/types.ts @@ -72,3 +72,16 @@ export type VoteEvent = { ballotType: BallotType ballot?: BallotConfigs } + +export type VoterInfo = { + estatus: string + numeroElectoral: string + precinto: string + unidad: string +} + +export type BallotsResponse = { + estatal: string + municipal: string + legislative: string +} diff --git a/src/services/api.ts b/src/services/api.ts new file mode 100644 index 00000000..4f4e8e0e --- /dev/null +++ b/src/services/api.ts @@ -0,0 +1,79 @@ +import { API_URL } from "../packages/practica/services/constants" + +interface RequestOptions { + baseUrl?: string +} + +interface ApiInterface { + get(endpoint: string, options?: RequestOptions): Promise + post(endpoint: string, params: any, options?: RequestOptions): Promise +} + +class FetchAdapter implements ApiInterface { + private baseUrl + + constructor(baseUrl: string) { + this.baseUrl = baseUrl + } + + private async processResponse(res: Response) { + if (!res.ok) { + throw Error("Network request failed.") + } + + const data: T = await res.json() + + return data + } + + private getBaseUrl(options?: RequestOptions) { + if (options && options.baseUrl) { + return options.baseUrl + } + + return this.baseUrl + } + + async get(endpoint: string, options?: RequestOptions) { + const baseUrl = this.getBaseUrl(options) + const res = await fetch(`${baseUrl}${endpoint}`) + const data = await this.processResponse(res) + + return data + } + + async post(endpoint: string, params: any, options?: RequestOptions) { + const baseUrl = this.getBaseUrl(options) + const res = await fetch(`${baseUrl}${endpoint}`, { + method: "POST", + body: JSON.stringify(params), + }) + const data = await this.processResponse(res) + + return data + } +} + +class ApiService { + private adapter + + constructor(adapter: ApiInterface) { + this.adapter = adapter + } + + async get(endpoint: string, options?: RequestOptions) { + const res = await this.adapter.get(endpoint, options) + + return res + } + + async post(endpoint: string, params: any, options?: RequestOptions) { + const res = await this.adapter.post(endpoint, params, options) + + return res + } +} + +const adapter = new FetchAdapter(API_URL) + +export default new ApiService(adapter)