diff --git a/etc/fetchers/__mocks__/vaksinid-locations-aceh.json b/etc/fetchers/__mocks__/vaksinid-locations-aceh.json new file mode 100644 index 00000000..80c070d3 --- /dev/null +++ b/etc/fetchers/__mocks__/vaksinid-locations-aceh.json @@ -0,0 +1,26 @@ +{ + "data": [ + { + "province": "Aceh", + "city": "Kota Banda Aceh", + "title": "UPTD PUSKESMAS KOPELMA DARUSSALAM", + "datestart": "2021-06-24", + "dateend": "2022-03-31", + "timestart": "08:00:00", + "timeend": "12:00:00", + "registration": "Walk-in", + "agerange": [ + "Dewasa (18-59 Tahun)", + "Lansia (60-)" + ], + "description": "-Senin dan Sabtu (bisa berubah sewaktu-waktu)\n-Dibeikan bagi warga dengan kriteria:\n1.petugas pelayanan publik\n2. Pra lansia &lansia\n3. Masyarakat Banda Aceh di utamakan yang berdomisili di wilayah Puskesmas Kopelma Darussalam,Rukoh,ie masen kayee adang,Lamgugob & Deah raya\n-Membawa KTP\n-informasi tambahan bisa dilihat di akun Instagram https://instagram.com/puskesmaskopelmadarussalam?utm_medium=copy_link", + "link": "https://www.instagram.com/p/CQgFAepnZkQ/?utm_medium=copy_link", + "address": "Jalan Inong Balee No.38 Darussalam Banda Aceh", + "map": "https://goo.gl/maps/9hViESZJ9rYwGypb9", + "isfree": true, + "isvalid": true, + "code": "", + "dateadded": "2021-07-30" + } + ] +} diff --git a/etc/fetchers/__mocks__/vaksinid-regions.json b/etc/fetchers/__mocks__/vaksinid-regions.json new file mode 100644 index 00000000..3136fe3d --- /dev/null +++ b/etc/fetchers/__mocks__/vaksinid-regions.json @@ -0,0 +1,15 @@ +{ + "data": [ + { + "province": "Aceh", + "city": [ + "Kota Banda Aceh", + "Kota Sabang", + "Kota Lhokseumawe", + "Kota Langsa", + "Kota Subulussalam", + "Kab. Aceh Selatan" + ] + } + ] +} diff --git a/etc/fetchers/__mocks__/wbw-vaccination-db.json b/etc/fetchers/__mocks__/wbw-vaccination-db.json new file mode 100644 index 00000000..fe0a270f --- /dev/null +++ b/etc/fetchers/__mocks__/wbw-vaccination-db.json @@ -0,0 +1,22 @@ +{ + "Aceh": [ + { + "alamat": "Jalan Inong Balee No.38 Darussalam Banda Aceh", + "lokasi": "Kota Banda Aceh", + "buka_waktu": "08:00:00", + "id": "0", + "informasi_2": "-Senin dan Sabtu (bisa berubah sewaktu-waktu)\n-Dibeikan bagi warga dengan kriteria:\n1.petugas pelayanan publik\n2. Pra lansia &lansia\n3. Masyarakat Banda Aceh di utamakan yang berdomisili di wilayah Puskesmas Kopelma Darussalam,Rukoh,ie masen kayee adang,Lamgugob & Deah raya\n-Membawa KTP\n-informasi tambahan bisa dilihat di akun Instagram https://instagram.com/puskesmaskopelmadarussalam?utm_medium=copy_link", + "keterangan": "Lokasi Vaksinasi COVID-19", + "link": "https://www.instagram.com/p/CQgFAepnZkQ/?utm_medium=copy_link", + "map": "https://goo.gl/maps/9hViESZJ9rYwGypb9", + "mulai_tanggal": "2021-06-24", + "penyedia": "UPTD PUSKESMAS KOPELMA DARUSSALAM", + "rentang_umur": ["Dewasa (18-59 Tahun)", "Lansia (60-)"], + "selesai_tanggal": "2022-03-31", + "slug": "uptd-puskesmas-kopelma-darussalam", + "terakhir_update": "2021-07-30", + "tutup_waktu": "12:00:00", + "verifikasi": 1 + } + ] +} diff --git a/etc/fetchers/__tests__/fetch-vaccination-database.test.ts b/etc/fetchers/__tests__/fetch-vaccination-database.test.ts new file mode 100644 index 00000000..230213fa --- /dev/null +++ b/etc/fetchers/__tests__/fetch-vaccination-database.test.ts @@ -0,0 +1,53 @@ +import fs from "fs"; +import path from "path"; +import fetchMock from "jest-fetch-mock"; +import { fetchVaccinationDatabase } from "../fetch-vaccination-database"; + +describe("fetchVaksinasiDB", () => { + const writeFileSyncSpy = jest.spyOn(fs, "writeFileSync"); + + beforeEach(() => { + fetchMock.resetMocks(); + writeFileSyncSpy.mockImplementation(() => {}); + }); + + afterEach(() => { + writeFileSyncSpy.mockRestore(); + }); + it("fetches database from api.vaksinasi.id correctly", async () => { + const mockedResponses: { [url: string]: string } = { + "/regions": fs.readFileSync( + path.resolve(__dirname, "../__mocks__/vaksinid-regions.json"), + "utf-8", + ), + "/locations/Aceh": fs.readFileSync( + path.resolve(__dirname, "../__mocks__/vaksinid-locations-aceh.json"), + "utf-8", + ), + }; + + fetchMock.mockResponse( + async (req) => + mockedResponses[new URL(req.url).pathname] || + '{ "details":"Not Found" }', + ); + await fetchVaccinationDatabase(); + + expect(fetchMock).toBeCalledTimes(2); + + expect(fetchMock).toBeCalledWith("https://api.vaksinasi.id/regions"); + expect(fetchMock).toHaveBeenCalledWith( + "https://api.vaksinasi.id/locations/Aceh", + ); + + expect(writeFileSyncSpy).toHaveBeenCalledTimes(1); + expect(JSON.parse(writeFileSyncSpy.mock.calls[0][1] as string)).toEqual( + JSON.parse( + fs.readFileSync( + path.resolve(__dirname, "../__mocks__/wbw-vaccination-db.json"), + "utf-8", + ), + ), + ); + }); +}); diff --git a/etc/fetchers/fetch-vaccination-database.ts b/etc/fetchers/fetch-vaccination-database.ts new file mode 100644 index 00000000..c9590b31 --- /dev/null +++ b/etc/fetchers/fetch-vaccination-database.ts @@ -0,0 +1,57 @@ +import fs from "fs"; +import path from "path"; +import fetch from "cross-fetch"; +import { + VaccinationRegionsResponse, + VaccinationRegion, + VaccinationContact, +} from "../../lib/data/vaccination"; +import { getKebabCase } from "../../lib/string-utils"; + +const vaksinId = "https://api.vaksinasi.id"; + +export async function fetchVaccinationDatabase() { + const regions = (await ( + await fetch(`${vaksinId}/regions`) + ).json()) as VaccinationRegionsResponse; + + const locations: { [province: string]: VaccinationContact[] } = {}; + + const promisedLocations = []; + for (const { province } of regions.data) { + promisedLocations.push( + fetch(`${vaksinId}/locations/${province}`) + .then((res) => res.json() as unknown as VaccinationRegion) + .then((region) => { + locations[region.data[0].province] = region.data.map((location) => ({ + id: `${region.data.findIndex( + (index) => location.title === index.title, + )}`, + keterangan: "Lokasi Vaksinasi COVID-19", + lokasi: location.city, + verifikasi: location.isvalid ? 1 : 0, + penyedia: location.title, + alamat: location.address, + slug: getKebabCase(location.title), + informasi_2: location.description, + terakhir_update: location.dateadded, + rentang_umur: location.agerange, + buka_waktu: location.timestart, + tutup_waktu: location.timeend, + mulai_tanggal: location.datestart, + selesai_tanggal: location.dateend, + link: location.link, + map: location.map, + })); + }), + ); + } + + await Promise.all(promisedLocations); + + const text = JSON.stringify(locations); + fs.writeFileSync( + path.resolve(__dirname, "../../data/wbw-vaccination-database.json"), + text, + ); +} diff --git a/etc/fetchers/fetch-wbw.ts b/etc/fetchers/fetch-wbw.ts index f3920427..42efb39f 100644 --- a/etc/fetchers/fetch-wbw.ts +++ b/etc/fetchers/fetch-wbw.ts @@ -4,11 +4,25 @@ import { toSecond } from "../../lib/string-utils"; import { fetchDatabase } from "./fetch-database"; import { fetchFaqSheets } from "./fetch-faq-sheets"; import { fetchSheets } from "./fetch-sheets"; +import { fetchVaccinationDatabase } from "./fetch-vaccination-database"; (function fetchWbw() { const start = process.hrtime(); const spinner = ora(`${chalk.yellowBright("Fetching all data...")}`).start(); + fetchVaccinationDatabase() + .then(() => { + const end = `${toSecond(process.hrtime(start))} seconds`; + spinner.succeed( + `Fetching vaccination database (vaksinasi.id) done in ${chalk.greenBright( + end, + )}`, + ); + }) + .catch((err) => { + chalk.red(err); + }); + fetchFaqSheets() .then(() => { const end = `${toSecond(process.hrtime(start))} seconds`; diff --git a/lib/data/vaccination.ts b/lib/data/vaccination.ts new file mode 100644 index 00000000..d7b5e548 --- /dev/null +++ b/lib/data/vaccination.ts @@ -0,0 +1,53 @@ +import { Contact } from "./provinces"; + +type City = `${"Kab." | "Kota"} ${string}`; +type DateString = `${number}-${number}-${number}`; +type TimeString = `${number}:${number}:${number}`; +type VaccinationAgeRange = Array<`${string} (${number}-${ + | number + | null} Tahun)`>; + +export interface VaccinationRegions { + province: string; + city: Array; +} + +export interface VaccinationRegionsResponse { + data: Array; +} +export interface VaccinationLocation { + province: string; + city: City; + title: string; + datestart: DateString; + dateend: DateString; + timestart: TimeString; + timeend: TimeString; + registration: string; + agerange: VaccinationAgeRange; + description: string; + link: string; + address: string; + map: string; + isFree: boolean; + isvalid: boolean; + code: string; + dateadded: DateString; +} + +type _location = VaccinationLocation; +export interface VaccinationRegion { + data: Array; +} + +export interface VaccinationContact extends Contact { + rentang_umur: _location["agerange"]; + buka_waktu: _location["timestart"]; + tutup_waktu: _location["timeend"]; + mulai_tanggal: _location["datestart"]; + selesai_tanggal: _location["dateend"]; + kode?: _location["code"]; + gratis?: _location["isFree"]; + map: _location["map"]; + link: _location["link"]; +} diff --git a/package.json b/package.json index b1ef2a1f..d9e6e508 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "lint": "eslint \"**/*.{js,jsx,ts,tsx,yml,yaml}\"", "lint:fix": "eslint --fix \"**/*.{js,jsx,ts,tsx,yml,yaml}\"", "mirror-box": "ts-node etc/mirror-box.ts", - "netlify-export": "yarn mirror-box && yarn build && next export", + "netlify-export": "yarn fetch-wbw && yarn build && next export", "prepare": "husky install", "start": "next start", "cypress:open": "cypress open",