├── functions ├── .eslintignore ├── src │ ├── graphql │ │ ├── typeDefs │ │ │ ├── scalars │ │ │ │ └── Date.graphql │ │ │ ├── queries │ │ │ │ ├── PPEQuery.graphql │ │ │ │ ├── Metadata.graphql │ │ │ │ ├── HealthFacilityCapacityQuery.graphql │ │ │ │ ├── LocationQuery.graphql │ │ │ │ ├── RatioUniqueIndQuery.graphql │ │ │ │ ├── TestingQuery.graphql │ │ │ │ └── CasesQuery.graphql │ │ │ ├── TestingFacility.graphql │ │ │ ├── DateValue.graphql │ │ │ ├── enums │ │ │ │ ├── RemovalType.graphql │ │ │ │ ├── QuarantineStatus.graphql │ │ │ │ ├── Sex.graphql │ │ │ │ ├── PregnancyStatus.graphql │ │ │ │ └── HealthStatus.graphql │ │ │ ├── DateValueFloat.graphql │ │ │ ├── HealthFacility.graphql │ │ │ ├── PSGCRegion.graphql │ │ │ ├── Residence.graphql │ │ │ ├── CountPerSex.graphql │ │ │ ├── PSGCProvince.graphql │ │ │ ├── TestingDailyOutput.graphql │ │ │ ├── index.ts │ │ │ ├── DistributionAgeGroupSex.graphql │ │ │ ├── TestingRatioUniqueInd.graphql │ │ │ ├── Query.graphql │ │ │ ├── TestingAggregate.graphql │ │ │ ├── PSGCCityMunicipality.graphql │ │ │ ├── TestingTotals.graphql │ │ │ ├── PPEReport.graphql │ │ │ ├── CaseInformation.graphql │ │ │ └── HealthFacilityCapacityReport.graphql │ │ ├── mocks │ │ │ ├── Date.ts │ │ │ └── index.ts │ │ ├── resolvers │ │ │ ├── enums │ │ │ │ ├── RemovalType.ts │ │ │ │ ├── Sex.ts │ │ │ │ └── QuarantineStatus.ts │ │ │ ├── queries │ │ │ │ ├── MetadataQuery.ts │ │ │ │ ├── PPEQuery.ts │ │ │ │ ├── HealthFacilityCapacityQuery.ts │ │ │ │ ├── LocationQuery.ts │ │ │ │ ├── RatioUniqueIndQuery.ts │ │ │ │ ├── TestingQuery.ts │ │ │ │ └── CasesQuery.ts │ │ │ ├── index.ts │ │ │ ├── Query.ts │ │ │ └── scalars │ │ │ │ └── Date.ts │ │ └── dataSources │ │ │ ├── PHLocations │ │ │ ├── index.ts │ │ │ └── PHLocations.ts │ │ │ ├── DataDropDailyReport │ │ │ ├── index.ts │ │ │ ├── DataDropDailyReport.ts │ │ │ ├── HealthFacilityCapacityReports.ts │ │ │ └── toHealthFacilityCapacityReport.ts │ │ │ ├── DataDropWeeklyReport │ │ │ ├── index.ts │ │ │ ├── DataDropWeeklyReport.ts │ │ │ ├── PPEReports.ts │ │ │ └── toPPEReport.ts │ │ │ ├── DataDropCaseInformation │ │ │ ├── index.ts │ │ │ ├── Cases.ts │ │ │ ├── toCaseInformation.ts │ │ │ └── DataDropCaseInformation.ts │ │ │ ├── DataDropTestingAggregates │ │ │ ├── index.ts │ │ │ ├── TestingAggregates.ts │ │ │ ├── toTestingAggregates.ts │ │ │ └── DataDropTestingAggregates.ts │ │ │ └── index.ts │ ├── consts │ │ ├── dateFirstCase.ts │ │ └── dateFirstTestingRecorded.ts │ ├── utils │ │ ├── between.ts │ │ ├── stripAltName.ts │ │ ├── stripFacilityName.ts │ │ ├── toAge.ts │ │ ├── toBoolean.ts │ │ ├── toNullableString.ts │ │ ├── toCity.ts │ │ ├── toFacilityName.ts │ │ ├── toSex.ts │ │ ├── toNullableInt.ts │ │ ├── toRemovalType.ts │ │ ├── dateRangeArray.ts │ │ ├── toPregnancyStatus.ts │ │ ├── toQuarantined.ts │ │ ├── toRegion.ts │ │ ├── toDate.ts │ │ ├── toProvince.ts │ │ └── toHealthStatus.ts │ ├── services │ │ ├── index.ts │ │ └── apollo.ts │ ├── types │ │ ├── DateValue.ts │ │ ├── RemovalType.ts │ │ ├── Sex.ts │ │ ├── HealthFacility.ts │ │ ├── TestingFacility.ts │ │ ├── CountPerSex.ts │ │ ├── PregnancyStatus.ts │ │ ├── QuarantineStatus.ts │ │ ├── DistributionAgeGroupSex.ts │ │ ├── HealthStatus.ts │ │ ├── PPEReport.ts │ │ ├── HealthFacilityCapacityReport.ts │ │ ├── AgeGroup.ts │ │ ├── TestingAggregate.ts │ │ └── CaseInformation.ts │ ├── middlewares │ │ ├── index.ts │ │ ├── cors.ts │ │ └── rateLimit.ts │ ├── index.ts │ ├── bin │ │ └── serve.ts │ ├── firebase.ts │ ├── apollo.ts │ ├── express.ts │ └── environment.ts ├── ANNOTATIONS ├── tsconfig.json ├── .eslintrc.json └── package.json ├── hosting ├── src │ ├── react-app-env.d.ts │ ├── main.css │ ├── setupTests.ts │ ├── components │ │ ├── ExternalLink.tsx │ │ ├── SectionTitle.tsx │ │ ├── CodeBlockJson.tsx │ │ ├── StarButton.tsx │ │ ├── IssueButton.tsx │ │ └── TryButton.tsx │ ├── sections │ │ ├── RateLimit.tsx │ │ ├── DataSource.tsx │ │ ├── License.tsx │ │ ├── Contributing.tsx │ │ ├── GraphQL.tsx │ │ └── Updates.tsx │ ├── App.tsx │ ├── index.tsx │ ├── Main.tsx │ └── serviceWorker.ts ├── public │ ├── favicon.ico │ ├── robots.txt │ ├── apple-icon.png │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon-96x96.png │ ├── logo1200x630.png │ ├── ms-icon-70x70.png │ ├── ms-icon-144x144.png │ ├── ms-icon-150x150.png │ ├── ms-icon-310x310.png │ ├── android-icon-36x36.png │ ├── android-icon-48x48.png │ ├── android-icon-72x72.png │ ├── android-icon-96x96.png │ ├── apple-icon-114x114.png │ ├── apple-icon-120x120.png │ ├── apple-icon-144x144.png │ ├── apple-icon-152x152.png │ ├── apple-icon-180x180.png │ ├── apple-icon-57x57.png │ ├── apple-icon-60x60.png │ ├── apple-icon-72x72.png │ ├── apple-icon-76x76.png │ ├── android-icon-144x144.png │ ├── android-icon-192x192.png │ ├── apple-icon-precomposed.png │ ├── browserconfig.xml │ ├── manifest.json │ └── index.html ├── tsconfig.json └── package.json ├── .firebaserc ├── .gitignore ├── LICENSE ├── firebase.json ├── .github └── stale.yml └── README.md /functions/.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist/ 3 | -------------------------------------------------------------------------------- /functions/src/graphql/typeDefs/scalars/Date.graphql: -------------------------------------------------------------------------------- 1 | scalar Date -------------------------------------------------------------------------------- /functions/src/consts/dateFirstCase.ts: -------------------------------------------------------------------------------- 1 | export default '2020-01-30'; 2 | -------------------------------------------------------------------------------- /hosting/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /functions/src/consts/dateFirstTestingRecorded.ts: -------------------------------------------------------------------------------- 1 | export default '2020-04-02'; 2 | -------------------------------------------------------------------------------- /functions/src/graphql/mocks/Date.ts: -------------------------------------------------------------------------------- 1 | export default (): string => '2020-03-24'; 2 | -------------------------------------------------------------------------------- /.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "ncovidtracker-api" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /hosting/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hubertursua/ncovph/HEAD/hosting/public/favicon.ico -------------------------------------------------------------------------------- /hosting/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /hosting/public/apple-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hubertursua/ncovph/HEAD/hosting/public/apple-icon.png -------------------------------------------------------------------------------- /hosting/public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hubertursua/ncovph/HEAD/hosting/public/favicon-16x16.png -------------------------------------------------------------------------------- /hosting/public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hubertursua/ncovph/HEAD/hosting/public/favicon-32x32.png -------------------------------------------------------------------------------- /hosting/public/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hubertursua/ncovph/HEAD/hosting/public/favicon-96x96.png -------------------------------------------------------------------------------- /hosting/public/logo1200x630.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hubertursua/ncovph/HEAD/hosting/public/logo1200x630.png -------------------------------------------------------------------------------- /hosting/public/ms-icon-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hubertursua/ncovph/HEAD/hosting/public/ms-icon-70x70.png -------------------------------------------------------------------------------- /functions/src/graphql/typeDefs/queries/PPEQuery.graphql: -------------------------------------------------------------------------------- 1 | # PPE query 2 | type PPEQuery { 3 | latest: [PPEReport] 4 | } 5 | -------------------------------------------------------------------------------- /hosting/public/ms-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hubertursua/ncovph/HEAD/hosting/public/ms-icon-144x144.png -------------------------------------------------------------------------------- /hosting/public/ms-icon-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hubertursua/ncovph/HEAD/hosting/public/ms-icon-150x150.png -------------------------------------------------------------------------------- /hosting/public/ms-icon-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hubertursua/ncovph/HEAD/hosting/public/ms-icon-310x310.png -------------------------------------------------------------------------------- /hosting/public/android-icon-36x36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hubertursua/ncovph/HEAD/hosting/public/android-icon-36x36.png -------------------------------------------------------------------------------- /hosting/public/android-icon-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hubertursua/ncovph/HEAD/hosting/public/android-icon-48x48.png -------------------------------------------------------------------------------- /hosting/public/android-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hubertursua/ncovph/HEAD/hosting/public/android-icon-72x72.png -------------------------------------------------------------------------------- /hosting/public/android-icon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hubertursua/ncovph/HEAD/hosting/public/android-icon-96x96.png -------------------------------------------------------------------------------- /hosting/public/apple-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hubertursua/ncovph/HEAD/hosting/public/apple-icon-114x114.png -------------------------------------------------------------------------------- /hosting/public/apple-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hubertursua/ncovph/HEAD/hosting/public/apple-icon-120x120.png -------------------------------------------------------------------------------- /hosting/public/apple-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hubertursua/ncovph/HEAD/hosting/public/apple-icon-144x144.png -------------------------------------------------------------------------------- /hosting/public/apple-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hubertursua/ncovph/HEAD/hosting/public/apple-icon-152x152.png -------------------------------------------------------------------------------- /hosting/public/apple-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hubertursua/ncovph/HEAD/hosting/public/apple-icon-180x180.png -------------------------------------------------------------------------------- /hosting/public/apple-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hubertursua/ncovph/HEAD/hosting/public/apple-icon-57x57.png -------------------------------------------------------------------------------- /hosting/public/apple-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hubertursua/ncovph/HEAD/hosting/public/apple-icon-60x60.png -------------------------------------------------------------------------------- /hosting/public/apple-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hubertursua/ncovph/HEAD/hosting/public/apple-icon-72x72.png -------------------------------------------------------------------------------- /hosting/public/apple-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hubertursua/ncovph/HEAD/hosting/public/apple-icon-76x76.png -------------------------------------------------------------------------------- /functions/src/graphql/resolvers/enums/RemovalType.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | RECOVERED: 'RECOVERED', 3 | DIED: 'DIED', 4 | }; 5 | -------------------------------------------------------------------------------- /functions/src/graphql/typeDefs/TestingFacility.graphql: -------------------------------------------------------------------------------- 1 | type TestingFacility { 2 | name: String! 3 | abbreviation: String 4 | } -------------------------------------------------------------------------------- /functions/src/utils/between.ts: -------------------------------------------------------------------------------- 1 | export default (val: number, start: number, end: number): boolean => (start <= val && val <= end); 2 | -------------------------------------------------------------------------------- /functions/src/utils/stripAltName.ts: -------------------------------------------------------------------------------- 1 | export default (str: string): string => str.replace(/\s\([A-Za-z0-9\-\s]+\)$/, '').trim(); 2 | -------------------------------------------------------------------------------- /functions/src/utils/stripFacilityName.ts: -------------------------------------------------------------------------------- 1 | export default (name: string): string => name.replace(/[^a-zA-Z\d]/g, '').toUpperCase(); 2 | -------------------------------------------------------------------------------- /hosting/public/android-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hubertursua/ncovph/HEAD/hosting/public/android-icon-144x144.png -------------------------------------------------------------------------------- /hosting/public/android-icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hubertursua/ncovph/HEAD/hosting/public/android-icon-192x192.png -------------------------------------------------------------------------------- /functions/src/graphql/dataSources/PHLocations/index.ts: -------------------------------------------------------------------------------- 1 | import PHLocations from './PHLocations'; 2 | 3 | export default PHLocations; 4 | -------------------------------------------------------------------------------- /hosting/public/apple-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hubertursua/ncovph/HEAD/hosting/public/apple-icon-precomposed.png -------------------------------------------------------------------------------- /functions/src/graphql/mocks/index.ts: -------------------------------------------------------------------------------- 1 | import Date from './Date'; 2 | 3 | const mocks = { 4 | Date, 5 | }; 6 | 7 | export default mocks; 8 | -------------------------------------------------------------------------------- /functions/src/graphql/resolvers/enums/Sex.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | FEMALE: 'FEMALE', 3 | MALE: 'MALE', 4 | UNKNOWN: 'UNKNOWN', 5 | }; 6 | -------------------------------------------------------------------------------- /functions/src/services/index.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/prefer-default-export */ 2 | 3 | export { default as apollo } from './apollo'; 4 | -------------------------------------------------------------------------------- /functions/src/types/DateValue.ts: -------------------------------------------------------------------------------- 1 | interface DateValue { 2 | date: string; 3 | value: number; 4 | } 5 | 6 | export default DateValue; 7 | -------------------------------------------------------------------------------- /functions/src/graphql/resolvers/enums/QuarantineStatus.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | UNKNOWN: 'UNKNOWN', 3 | YES: 'YES', 4 | NO: 'NO', 5 | }; 6 | -------------------------------------------------------------------------------- /functions/src/types/RemovalType.ts: -------------------------------------------------------------------------------- 1 | enum RemovalType { 2 | RECOVERED = 'RECOVERED', 3 | DIED = 'DIED', 4 | } 5 | 6 | export default RemovalType; 7 | -------------------------------------------------------------------------------- /functions/src/types/Sex.ts: -------------------------------------------------------------------------------- 1 | enum Sex { 2 | FEMALE = 'FEMALE', 3 | MALE = 'MALE', 4 | UNKNOWN = 'UNKNOWN', 5 | } 6 | 7 | export default Sex; 8 | -------------------------------------------------------------------------------- /hosting/src/main.css: -------------------------------------------------------------------------------- 1 | .inline-code { 2 | background: rgba(0,0,0, 0.08); 3 | border-radius: 4px; 4 | padding: 0 6px; 5 | font-size: 0.87em; 6 | } -------------------------------------------------------------------------------- /functions/src/graphql/typeDefs/queries/Metadata.graphql: -------------------------------------------------------------------------------- 1 | # Metadata Query 2 | type MetadataQuery { 3 | # Location 4 | location: LocationQuery 5 | } 6 | -------------------------------------------------------------------------------- /functions/src/types/HealthFacility.ts: -------------------------------------------------------------------------------- 1 | interface HealthFacility { 2 | code: string; 3 | 4 | name: string; 5 | } 6 | 7 | export default HealthFacility; 8 | -------------------------------------------------------------------------------- /functions/src/graphql/dataSources/DataDropDailyReport/index.ts: -------------------------------------------------------------------------------- 1 | import DataDropDailyReport from './DataDropDailyReport'; 2 | 3 | export default DataDropDailyReport; 4 | -------------------------------------------------------------------------------- /functions/src/types/TestingFacility.ts: -------------------------------------------------------------------------------- 1 | interface TestingFacility { 2 | name: string; 3 | abbreviation: string; 4 | } 5 | 6 | export default TestingFacility; 7 | -------------------------------------------------------------------------------- /functions/src/graphql/dataSources/DataDropWeeklyReport/index.ts: -------------------------------------------------------------------------------- 1 | import DataDropWeeklyReport from './DataDropWeeklyReport'; 2 | 3 | export default DataDropWeeklyReport; 4 | -------------------------------------------------------------------------------- /functions/src/types/CountPerSex.ts: -------------------------------------------------------------------------------- 1 | interface CountPerSex { 2 | female: number; 3 | male: number; 4 | unknown: number; 5 | } 6 | 7 | export default CountPerSex; 8 | -------------------------------------------------------------------------------- /functions/src/middlewares/index.ts: -------------------------------------------------------------------------------- 1 | import * as cors from './cors'; 2 | import * as rateLimit from './rateLimit'; 3 | 4 | export default { 5 | cors, 6 | rateLimit, 7 | }; 8 | -------------------------------------------------------------------------------- /functions/src/types/PregnancyStatus.ts: -------------------------------------------------------------------------------- 1 | enum PregnancyStatus { 2 | UNKNOWN = 'UNKNOWN', 3 | NO = 'NO', 4 | YES = 'YES', 5 | } 6 | 7 | export default PregnancyStatus; 8 | -------------------------------------------------------------------------------- /functions/src/types/QuarantineStatus.ts: -------------------------------------------------------------------------------- 1 | enum QuarantineStatus { 2 | UNKNOWN = 'UNKNOWN', 3 | YES = 'YES', 4 | NO = 'NO', 5 | } 6 | 7 | export default QuarantineStatus; 8 | -------------------------------------------------------------------------------- /functions/src/graphql/resolvers/queries/MetadataQuery.ts: -------------------------------------------------------------------------------- 1 | import LocationQuery from './LocationQuery'; 2 | 3 | export default { 4 | location: (): object => LocationQuery, 5 | }; 6 | -------------------------------------------------------------------------------- /functions/src/graphql/typeDefs/DateValue.graphql: -------------------------------------------------------------------------------- 1 | # Value per date 2 | type DateValue { 3 | # Date 4 | date: Date 5 | 6 | # Value for a particular date 7 | value: Int 8 | } -------------------------------------------------------------------------------- /functions/src/graphql/typeDefs/enums/RemovalType.graphql: -------------------------------------------------------------------------------- 1 | # Removal type (RECOVERED, DIED) 2 | enum RemovalType { 3 | # Recovered 4 | RECOVERED 5 | 6 | # Died 7 | DIED 8 | } -------------------------------------------------------------------------------- /functions/src/index.ts: -------------------------------------------------------------------------------- 1 | import './firebase'; // Pre-initialize firebase-admin 2 | import { 3 | apollo, 4 | } from './services'; 5 | 6 | module.exports = { 7 | apollo, 8 | }; 9 | -------------------------------------------------------------------------------- /functions/src/graphql/dataSources/DataDropCaseInformation/index.ts: -------------------------------------------------------------------------------- 1 | import DataDropCaseInformation from './DataDropCaseInformation'; 2 | 3 | export default DataDropCaseInformation; 4 | -------------------------------------------------------------------------------- /functions/src/graphql/dataSources/DataDropTestingAggregates/index.ts: -------------------------------------------------------------------------------- 1 | import DataDropTestingAggregates from './DataDropTestingAggregates'; 2 | 3 | export default DataDropTestingAggregates; 4 | -------------------------------------------------------------------------------- /functions/src/graphql/typeDefs/DateValueFloat.graphql: -------------------------------------------------------------------------------- 1 | # Value per date 2 | type DateValueFloat { 3 | # Date 4 | date: Date 5 | 6 | # Value for a particular date 7 | value: Float 8 | } -------------------------------------------------------------------------------- /functions/src/graphql/typeDefs/queries/HealthFacilityCapacityQuery.graphql: -------------------------------------------------------------------------------- 1 | # Health Facility Capacity Query 2 | type HealthFacilityCapacityQuery { 3 | latest: [HealthFacilityCapacityReport] 4 | } -------------------------------------------------------------------------------- /functions/src/graphql/typeDefs/enums/QuarantineStatus.graphql: -------------------------------------------------------------------------------- 1 | # Quarantine status 2 | enum QuarantineStatus { 3 | # Unknown 4 | UNKNOWN 5 | 6 | # Yes 7 | YES 8 | 9 | # No 10 | NO 11 | } -------------------------------------------------------------------------------- /functions/src/graphql/typeDefs/enums/Sex.graphql: -------------------------------------------------------------------------------- 1 | # Sex (FEMALE, MALE, UNKNOWN) 2 | enum Sex { 3 | # Female 4 | FEMALE 5 | 6 | # Male 7 | MALE 8 | 9 | # Unknown 10 | UNKNOWN 11 | } 12 | -------------------------------------------------------------------------------- /functions/src/graphql/typeDefs/enums/PregnancyStatus.graphql: -------------------------------------------------------------------------------- 1 | # Pregnancy Status 2 | enum PregnancyStatus { 3 | # Unknown 4 | UNKNOWN 5 | 6 | # No 7 | NO 8 | 9 | # Yes 10 | YES 11 | } 12 | -------------------------------------------------------------------------------- /functions/src/graphql/typeDefs/HealthFacility.graphql: -------------------------------------------------------------------------------- 1 | # Health Facility 2 | type HealthFacility { 3 | # Health facility's identification code (hfhudcode) 4 | code: String 5 | 6 | # Name 7 | name: String 8 | } -------------------------------------------------------------------------------- /functions/src/graphql/typeDefs/PSGCRegion.graphql: -------------------------------------------------------------------------------- 1 | # Region 2 | type PSGCRegion { 3 | # Code 4 | code: String! 5 | 6 | # Name 7 | name: String! 8 | 9 | # Alternate name 10 | altName: String 11 | } 12 | -------------------------------------------------------------------------------- /functions/src/graphql/typeDefs/Residence.graphql: -------------------------------------------------------------------------------- 1 | # Residence 2 | type Residence { 3 | # Region 4 | region: String 5 | 6 | # Province 7 | province: String 8 | 9 | # City or municipality 10 | city: String 11 | } -------------------------------------------------------------------------------- /functions/src/types/DistributionAgeGroupSex.ts: -------------------------------------------------------------------------------- 1 | interface DistributionAgeGroupSex { 2 | ageGroup: string; 3 | female: number; 4 | male: number; 5 | unknown: number; 6 | } 7 | 8 | export default DistributionAgeGroupSex; 9 | -------------------------------------------------------------------------------- /functions/src/utils/toAge.ts: -------------------------------------------------------------------------------- 1 | export default (str: string): number | null => { 2 | const val = Number.parseInt(str, 10); 3 | 4 | if (Number.isNaN(val)) { 5 | return null; 6 | } 7 | 8 | return val; 9 | }; 10 | -------------------------------------------------------------------------------- /functions/src/utils/toBoolean.ts: -------------------------------------------------------------------------------- 1 | export default (str: string): boolean => { 2 | const val = str.toUpperCase().trim(); 3 | 4 | if (['TRUE', 'YES', 'T', 'Y'].includes(val)) { 5 | return true; 6 | } 7 | 8 | return false; 9 | }; 10 | -------------------------------------------------------------------------------- /functions/src/graphql/typeDefs/CountPerSex.graphql: -------------------------------------------------------------------------------- 1 | # Total count per sex 2 | type CountPerSex { 3 | # Total for females 4 | female: Int 5 | 6 | # Total for males 7 | male: Int 8 | 9 | # Total for unknowns 10 | unknown: Int 11 | } 12 | -------------------------------------------------------------------------------- /functions/ANNOTATIONS: -------------------------------------------------------------------------------- 1 | [April 22, 2020] 2 | 3 | Testing Aggregates 4 | 5 | 1. April 21, 2020 Philippine Red Cross (PRC) Remaining Available Tests was 6 | changed from "≈70000" to "70000". The approximation was removed and pegged at 7 | the lowest number. -------------------------------------------------------------------------------- /functions/src/middlewares/cors.ts: -------------------------------------------------------------------------------- 1 | import cors from 'cors'; 2 | 3 | const options = { 4 | origin: '*', 5 | optionsSuccessStatus: 200, 6 | }; 7 | 8 | // eslint-disable-next-line import/prefer-default-export 9 | export const handler = cors(options); 10 | -------------------------------------------------------------------------------- /functions/src/graphql/typeDefs/PSGCProvince.graphql: -------------------------------------------------------------------------------- 1 | # Province 2 | type PSGCProvince { 3 | # Code 4 | code: String! 5 | 6 | # Name 7 | name: String! 8 | 9 | # Alternate name 10 | altName: String 11 | 12 | # Region code 13 | region: String! 14 | } 15 | -------------------------------------------------------------------------------- /functions/src/graphql/typeDefs/queries/LocationQuery.graphql: -------------------------------------------------------------------------------- 1 | # Location Query 2 | type LocationQuery { 3 | # Regions 4 | regions: [PSGCRegion] 5 | 6 | # Provinces 7 | provinces: [PSGCProvince] 8 | 9 | # Cities 10 | cities: [PSGCCityMunicipality] 11 | } 12 | -------------------------------------------------------------------------------- /functions/src/utils/toNullableString.ts: -------------------------------------------------------------------------------- 1 | export default (str: string): string | null => { 2 | if (!str) { 3 | return null; 4 | } 5 | 6 | const val = str.trim(); 7 | 8 | if (val === '') { 9 | return null; 10 | } 11 | 12 | 13 | return val; 14 | }; 15 | -------------------------------------------------------------------------------- /functions/src/bin/serve.ts: -------------------------------------------------------------------------------- 1 | import environment from '../environment'; 2 | import express from '../express'; 3 | 4 | express.listen({ port: environment.port }, () => { 5 | // eslint-disable-next-line no-console 6 | console.log(`Server ready at http://localhost:${environment.port}`); 7 | }); 8 | -------------------------------------------------------------------------------- /hosting/src/setupTests.ts: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom/extend-expect'; 6 | -------------------------------------------------------------------------------- /functions/src/types/HealthStatus.ts: -------------------------------------------------------------------------------- 1 | enum HealthStatus { 2 | UNKNOWN = 'UNKNOWN', 3 | ASYMPTOMATIC = 'ASYMPTOMATIC', 4 | MILD = 'MILD', 5 | SEVERE = 'SEVERE', 6 | CRITICAL = 'CRITICAL', 7 | RECOVERED = 'RECOVERED', 8 | DIED = 'DIED', 9 | } 10 | 11 | export default HealthStatus; 12 | -------------------------------------------------------------------------------- /hosting/src/components/ExternalLink.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export default function ExternalLink({ href, label }: { href: string, label: string }) { 4 | return ( 5 | 6 | {label} 7 | 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /hosting/src/components/SectionTitle.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Heading } from "grommet"; 3 | 4 | export default function SectionTitle({ title }: { title: string; }) { 5 | return ( 6 | 7 | {title} 8 | 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /functions/src/services/apollo.ts: -------------------------------------------------------------------------------- 1 | 2 | import * as functions from 'firebase-functions'; 3 | import express from '../express'; 4 | 5 | export default functions 6 | .region('us-central1') 7 | .runWith({ 8 | memory: '256MB', 9 | timeoutSeconds: 30, 10 | }) 11 | .https.onRequest(express); 12 | -------------------------------------------------------------------------------- /hosting/public/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | #ffffff -------------------------------------------------------------------------------- /functions/src/graphql/typeDefs/TestingDailyOutput.graphql: -------------------------------------------------------------------------------- 1 | type TestingDailyOutput { 2 | # Daily Output - Positive Individuals 3 | positiveInd: Int 4 | 5 | # Daily Output - Unique Individuals Tested 6 | uniqueIndTested: Int 7 | 8 | # Daily Output - Tests Conducted 9 | testsConducted: Int 10 | } 11 | -------------------------------------------------------------------------------- /functions/src/graphql/typeDefs/index.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import glob from 'glob'; 3 | 4 | const files = glob.sync(`${__dirname}/**/*.graphql`); 5 | 6 | const typeDefs = files 7 | .map((file) => fs.readFileSync(file, { encoding: 'utf8' }).trim()) 8 | .join('\n\n'); 9 | 10 | export default typeDefs; 11 | -------------------------------------------------------------------------------- /functions/src/utils/toCity.ts: -------------------------------------------------------------------------------- 1 | import stripAltName from './stripAltName'; 2 | 3 | export default (city: string | null): string | null => { 4 | if (!city) { 5 | return null; 6 | } 7 | 8 | const citySanitized = stripAltName(city).replace('For Validation', '') || null; 9 | 10 | return citySanitized; 11 | }; 12 | -------------------------------------------------------------------------------- /functions/src/graphql/typeDefs/DistributionAgeGroupSex.graphql: -------------------------------------------------------------------------------- 1 | # Distribution of sex per age group 2 | type DistributionAgeGroupSex { 3 | # Age group 4 | ageGroup: String 5 | 6 | # Total for females 7 | female: Int 8 | 9 | # Total for males 10 | male: Int 11 | 12 | # Total for unknowns 13 | unknown: Int 14 | } 15 | -------------------------------------------------------------------------------- /functions/src/utils/toFacilityName.ts: -------------------------------------------------------------------------------- 1 | import stripAltName from './stripAltName'; 2 | import toNullableString from './toNullableString'; 3 | 4 | export default (str: string): string | null => { 5 | const val = toNullableString(str); 6 | 7 | if (val === null) { 8 | return null; 9 | } 10 | 11 | return stripAltName(val); 12 | }; 13 | -------------------------------------------------------------------------------- /functions/src/graphql/typeDefs/enums/HealthStatus.graphql: -------------------------------------------------------------------------------- 1 | # Health status 2 | enum HealthStatus { 3 | # Unknown 4 | UNKNOWN 5 | 6 | # Asymptomatic 7 | ASYMPTOMATIC 8 | 9 | # Mild 10 | MILD 11 | 12 | # Severe 13 | SEVERE 14 | 15 | # Critical 16 | CRITICAL 17 | 18 | # Recovered 19 | RECOVERED 20 | 21 | # Died 22 | DIED 23 | } 24 | -------------------------------------------------------------------------------- /functions/src/graphql/typeDefs/TestingRatioUniqueInd.graphql: -------------------------------------------------------------------------------- 1 | type TestingRatioUniqueInd { 2 | # % positive/ unique individuals 3 | positiveInd: Float 4 | 5 | # % negative/unique individuals 6 | negativeInd: Float 7 | 8 | # % equivocal /unique individuals 9 | equivocalInd: Float 10 | 11 | # % invalid /unique individuals 12 | invalidInd: Float 13 | } -------------------------------------------------------------------------------- /functions/src/utils/toSex.ts: -------------------------------------------------------------------------------- 1 | import Sex from '../types/Sex'; 2 | 3 | export default (str: string): Sex | null => { 4 | const val = str.toUpperCase().trim(); 5 | 6 | if (['F', 'FEMALE'].includes(val)) { 7 | return Sex.FEMALE; 8 | } 9 | 10 | if (['M', 'MALE'].includes(val)) { 11 | return Sex.MALE; 12 | } 13 | 14 | return Sex.UNKNOWN; 15 | }; 16 | -------------------------------------------------------------------------------- /functions/src/utils/toNullableInt.ts: -------------------------------------------------------------------------------- 1 | export default (str: string | number): number | null => { 2 | if (str === null) { 3 | return null; 4 | } 5 | 6 | const val = (typeof str === 'number') 7 | ? str.toString() 8 | : str.replace(',', '').trim(); 9 | 10 | if (val === '') { 11 | return null; 12 | } 13 | 14 | return parseInt(val, 10); 15 | }; 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env* 2 | dist 3 | build 4 | node_modules 5 | .idea 6 | .vscode 7 | *.log 8 | 9 | /package.json 10 | /package-lock.json 11 | 12 | ## Compiled JavaScript files 13 | **/*.js 14 | **/*.js.map 15 | 16 | # Typescript v1 declaration files 17 | typings/ 18 | 19 | # Firebase 20 | firebase-debug.log 21 | .firebase 22 | serviceAccountKey.json 23 | 24 | # App-specific 25 | functions/tmp -------------------------------------------------------------------------------- /functions/src/utils/toRemovalType.ts: -------------------------------------------------------------------------------- 1 | import RemovalType from '../types/RemovalType'; 2 | 3 | export default (str: string): RemovalType | null => { 4 | const val = str.toUpperCase().trim(); 5 | 6 | if (val === 'RECOVERED') { 7 | return RemovalType.RECOVERED; 8 | } 9 | 10 | if (val === 'DIED') { 11 | return RemovalType.DIED; 12 | } 13 | 14 | return null; 15 | }; 16 | -------------------------------------------------------------------------------- /functions/src/graphql/typeDefs/Query.graphql: -------------------------------------------------------------------------------- 1 | # Query 2 | type Query { 3 | # Hello 4 | hello: String 5 | 6 | # Cases 7 | cases: CasesQuery 8 | 9 | # Testing 10 | testing: TestingQuery 11 | 12 | # PPE 13 | ppe: PPEQuery 14 | 15 | # Health Facility Capacity 16 | healthFacilityCapacity: HealthFacilityCapacityQuery 17 | 18 | # Metadata 19 | metadata: MetadataQuery 20 | } -------------------------------------------------------------------------------- /functions/src/graphql/typeDefs/TestingAggregate.graphql: -------------------------------------------------------------------------------- 1 | type TestingAggregate { 2 | # Date 3 | date: Date! 4 | 5 | # Facility 6 | facility: TestingFacility! 7 | 8 | # Daily output 9 | dailyOutput: TestingDailyOutput! 10 | 11 | # Testing totals 12 | totals: TestingTotals! 13 | 14 | # Ratio over unique indiduals tested 15 | ratioUniqueInd: TestingRatioUniqueInd! 16 | } 17 | -------------------------------------------------------------------------------- /hosting/src/sections/RateLimit.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Box, Paragraph } from "grommet"; 3 | import SectionTitle from "../components/SectionTitle"; 4 | 5 | export default function RateLimit(): JSX.Element { 6 | return ( 7 | 8 | 9 | 45 requests per minute 10 | 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /functions/src/middlewares/rateLimit.ts: -------------------------------------------------------------------------------- 1 | import expressRateLimit from 'express-rate-limit'; 2 | import environment from '../environment'; 3 | 4 | // eslint-disable-next-line import/prefer-default-export 5 | export const handler = expressRateLimit({ 6 | windowMs: environment.rateLimit.windowMs, 7 | max: environment.rateLimit.max, 8 | message: { error: 'Too many requests. Slow down.' }, 9 | }); 10 | -------------------------------------------------------------------------------- /hosting/src/components/CodeBlockJson.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import SyntaxHighlighter from "react-syntax-highlighter"; 3 | import { docco } from "react-syntax-highlighter/dist/esm/styles/hljs"; 4 | 5 | export default function CodeBlockJson({ code }: { code: string }) { 6 | return ( 7 | 8 | {code} 9 | 10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /hosting/src/components/StarButton.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import GitHubButton from "react-github-btn"; 3 | 4 | export default function StarButton() { 5 | return ( 6 | 12 | Star 13 | 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /functions/src/utils/dateRangeArray.ts: -------------------------------------------------------------------------------- 1 | import moment from 'moment'; 2 | 3 | export default (start: string, end: string = null): string[] => { 4 | const arr = []; 5 | const pointer = moment(start); 6 | const endPointer = moment(end || new Date()); 7 | 8 | while (pointer.valueOf() <= endPointer.valueOf()) { 9 | arr.push(pointer.format('YYYY-MM-DD')); 10 | pointer.add(1, 'day'); 11 | } 12 | 13 | return arr; 14 | }; 15 | -------------------------------------------------------------------------------- /functions/src/utils/toPregnancyStatus.ts: -------------------------------------------------------------------------------- 1 | import PregnancyStatus from '../types/PregnancyStatus'; 2 | import toNullableString from './toNullableString'; 3 | 4 | export default (str: string): PregnancyStatus => { 5 | const val = toNullableString(str); 6 | 7 | if (!val) { 8 | return PregnancyStatus.UNKNOWN; 9 | } 10 | 11 | return (val.toUpperCase() === 'YES') 12 | ? PregnancyStatus.YES 13 | : PregnancyStatus.NO; 14 | }; 15 | -------------------------------------------------------------------------------- /hosting/src/components/IssueButton.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import GitHubButton from "react-github-btn"; 3 | 4 | export default function IssueButton() { 5 | return ( 6 | 12 | Issue 13 | 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /functions/src/utils/toQuarantined.ts: -------------------------------------------------------------------------------- 1 | import QuarantineStatus from '../types/QuarantineStatus'; 2 | import toNullableString from './toNullableString'; 3 | 4 | export default (str: string): QuarantineStatus => { 5 | const val = toNullableString(str); 6 | 7 | if (!val) { 8 | return QuarantineStatus.UNKNOWN; 9 | } 10 | 11 | return (val.toUpperCase() === 'YES') 12 | ? QuarantineStatus.YES 13 | : QuarantineStatus.NO; 14 | }; 15 | -------------------------------------------------------------------------------- /functions/src/graphql/resolvers/queries/PPEQuery.ts: -------------------------------------------------------------------------------- 1 | import PPEReport from '../../../types/PPEReport'; 2 | import { DataSources } from '../../dataSources'; 3 | 4 | export interface Context { 5 | dataSources: DataSources; 6 | } 7 | 8 | export default { 9 | latest: ( 10 | _obj: unknown, 11 | _args: unknown, 12 | { dataSources }: Context, 13 | ): PPEReport[] => dataSources 14 | .DataDropWeeklyReport 15 | .getLatest(), 16 | }; 17 | -------------------------------------------------------------------------------- /functions/src/graphql/typeDefs/PSGCCityMunicipality.graphql: -------------------------------------------------------------------------------- 1 | # City and Municipality 2 | type PSGCCityMunicipality { 3 | # Code 4 | code: String! 5 | 6 | # Name 7 | name: String! 8 | 9 | # Full name 10 | fullName: String! 11 | 12 | # Alternate name 13 | altName: String 14 | 15 | # Province code 16 | province: String! 17 | 18 | # Classification (MUNICIPALITY or CITY) 19 | classification: String! 20 | 21 | # Is capital 22 | isCapital: Boolean! 23 | } 24 | -------------------------------------------------------------------------------- /hosting/src/components/TryButton.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Button } from "grommet"; 3 | 4 | export default function TryButton({ query }: { 5 | query: string; 6 | }): JSX.Element { 7 | return ( 8 |