Skip to content

Commit

Permalink
feat: added method recommendation based on location
Browse files Browse the repository at this point in the history
  • Loading branch information
khawarizmus committed Oct 1, 2023
1 parent 65c6f20 commit c8fd1fb
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 5 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
},
"dependencies": {
"adhan": "^4.4.3",
"country-locator": "^2.1.1",
"rxjs": "^7.5.6",
"tslog": "^4.4.4"
}
Expand Down
72 changes: 69 additions & 3 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/Base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ export class BaseCalculator {
calendar: this._prayerConfig.hijriCalendar ?? 'islamic-umalqura',
dateStyle: 'short',
})
const hijriMonth = hijriFormatter.format(date).split('/')[0]
const hijriMonth = hijriFormatter.formatDate(date).split('/')[0]
// check if the month is ramadan
if (parseInt(hijriMonth) === 9) {
if (method === Methods.UMM_AL_QURA || this._prayerConfig.adjustForRamadan) {
Expand Down
12 changes: 11 additions & 1 deletion src/Formatter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { FormatterConfig } from './types/FormatterConfig'
import type { FormattedTimeObject, TimeObject } from './types/TimeObject'
export class Formatter {
private _formatter!: Intl.DateTimeFormat
private _config!: FormatterConfig
Expand Down Expand Up @@ -31,10 +32,19 @@ export class Formatter {
}
}

public format(date: Date): string {
public formatDate(date: Date): string {
return this._formatter.format(date)
}

public formatPrayers(prayerTimes: TimeObject[]): FormattedTimeObject[] {
return prayerTimes.map((v) => {
return {
name: v.name,
time: this.formatDate(v.time),
}
})
}

public setFormatterOptions(newConfig: Partial<FormatterConfig>) {
// TODO: pull the timezone from coordinates
const { locale, ...options } = newConfig
Expand Down
46 changes: 46 additions & 0 deletions src/MethodRecommender.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { findCountryByCoordinate } from 'country-locator'
import { CountryMethods } from './data/methods'
import type { LngLatLike } from './types/LangLatLike'
import type { Methods } from './types/Methods'

const methodsMap = new WeakMap<WeakKey, Methods[]>(
Object.entries(CountryMethods).map(([country, methods]) => [Symbol(country), methods])
)

/**
* recommend methods to use from given coordinate
* the methods are ranked by the most used to the least used
* @param point - an array of two numbers - [x, y].
* PAY ATTENTION: x == longitude, y == latitude!
* @returns Methods[] | undefined - An array of recommended prayer methods for the given location, or undefined if the location is not found.
*/
export function MethodRecommender(coordinates: LngLatLike): Methods[] | undefined
/**
* recommend methods to use given coordinate
* the methods are ranked by the most used to the least used
* @param latitude - latitude of coordinate
* @param longitude - longitude of coordinate
* @returns Methods[] | undefined - An array of recommended prayer methods for the given location, or undefined if the location is not found.
*/
export function MethodRecommender(latitude: number, longitude: number): Methods[] | undefined

export function MethodRecommender(coordinatesOrLat: LngLatLike | number, longitude?: number): Methods[] | undefined {
const countryInfo = findCountryByCoordinate(
longitude ? [coordinatesOrLat as number, longitude] : getLngLat(coordinatesOrLat as LngLatLike)
)
return methodsMap.get(Symbol(countryInfo?.code))
}

function getLngLat(coordinates: LngLatLike): [number, number] {
if (Array.isArray(coordinates)) {
return coordinates
} else if ('lng' in coordinates && 'lat' in coordinates) {
return [coordinates.lng, coordinates.lat]
} else if ('lon' in coordinates && 'lat' in coordinates) {
return [coordinates.lon, coordinates.lat]
} else if ('longitude' in coordinates && 'latitude' in coordinates) {
return [coordinates.longitude, coordinates.latitude]
} else {
throw new Error('Invalid coordinates object')
}
}
41 changes: 41 additions & 0 deletions src/data/methods.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Methods } from '../types/Methods'

export const CountryMethods = {
SAU: [Methods.UMM_AL_QURA],
AFG: [Methods.KARACHI],
ALB: [Methods.MUSLIM_WORLD_LEAGUE],
ARE: [Methods.DUBAI],
BGD: [Methods.KARACHI],
BHR: [Methods.BAHRAIN],
BRN: [Methods.BRUNEI],
CAN: [Methods.NORTH_AMERICA, Methods.MUSLIM_WORLD_LEAGUE],
DEU: [Methods.GERMANY],
// DNK: ['Europe/Copenhagen'],
DZA: [Methods.ALGERIA],
EGY: [Methods.EGYPTIAN],
FRA: [Methods.FRANCE, Methods.NORTH_AMERICA, Methods.STANDARD],
GBR: [Methods.NORTH_AMERICA, Methods.MUSLIM_WORLD_LEAGUE, Methods.MOONSIGHTING_COMMITTEE],
IDN: [Methods.INDONESIA],
IND: [Methods.KARACHI],
IRN: [Methods.TEHRAN],
IRQ: [Methods.IRAQ],
ISR: [Methods.PALESTINE],
JOR: [Methods.JORDAN],
KWT: [Methods.KUWAIT],
LBN: [Methods.EGYPTIAN],
LBY: [Methods.LIBYA],
MAR: [Methods.MOROCCO],
MYS: [Methods.MALAYSIA],
OMN: [Methods.OMAN],
PAK: [Methods.KARACHI],
PSE: [Methods.PALESTINE],
QAT: [Methods.QATAR],
RUS: [Methods.RUSSIA],
// SDN: ['Africa/Khartoum'],
SGP: [Methods.SINGAPORE],
THA: [Methods.MALAYSIA],
TUN: [Methods.TUNISIA],
TUR: [Methods.TURKEY],
USA: [Methods.NORTH_AMERICA, Methods.MUSLIM_WORLD_LEAGUE, Methods.MOONSIGHTING_COMMITTEE, Methods.EGYPTIAN],
YEM: [Methods.YEMEN],
}
5 changes: 5 additions & 0 deletions src/types/LangLatLike.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export type CoordinatesObject =
| { lng: number; lat: number }
| { lon: number; lat: number }
| { longitude: number; latitude: number }
export type LngLatLike = [number, number] | CoordinatesObject

0 comments on commit c8fd1fb

Please sign in to comment.