feat: Add Diyanet API provider
feat: Add UI
This commit is contained in:
1 parent
d4ff42387f
commit
93af84cef8
17 files changed
+642
-43
No files matched your search
@@ -0,0 +1,208 @@
|
||||
const app = () => ({
|
||||
futureTimes: [],
|
||||
|
||||
locationId: Alpine.$persist('11104'),
|
||||
lastUpdated: Alpine.$persist(null),
|
||||
userMinutes: 0,
|
||||
now: new Date(),
|
||||
debug: location.hash === '#debug',
|
||||
geolocation: null,
|
||||
|
||||
async init() {
|
||||
await this.refreshIfStale();
|
||||
setInterval(() => {
|
||||
this.now = new Date();
|
||||
}, 500);
|
||||
|
||||
getUserLocation()
|
||||
.then(loc => {
|
||||
this.geolocation = {latitude: loc.latitude, longitude: loc.longitude};
|
||||
this.refreshIfStale();
|
||||
})
|
||||
.catch(() => this.geolocation = null)
|
||||
},
|
||||
|
||||
onHash() {
|
||||
this.debug = location.hash === '#debug'
|
||||
},
|
||||
|
||||
get userNow() {
|
||||
if (!this.debug) {
|
||||
return this.now;
|
||||
}
|
||||
|
||||
const d = new Date();
|
||||
d.setHours(0, this.userMinutes, 0, 0);
|
||||
return d;
|
||||
},
|
||||
|
||||
get userTime() {
|
||||
return formatTime(this.userNow);
|
||||
},
|
||||
|
||||
async refreshIfStale() {
|
||||
const updatedAt = new Date(this.lastUpdated);
|
||||
const now = new Date();
|
||||
|
||||
const elapsedSeconds = (now - updatedAt) / 1000;
|
||||
|
||||
if (this.geolocation !== null) {
|
||||
this.futureTimes = await fetchJSON(`/api/v1/diyanet/prayertimes?latitude=${this.geolocation.latitude}&longitude=${this.geolocation.longitude}`);
|
||||
} else {
|
||||
this.futureTimes = await fetchJSON(`/api/v1/diyanet/prayertimes?location_id=${this.locationId}`);
|
||||
}
|
||||
this.lastUpdated = now.toISOString();
|
||||
},
|
||||
|
||||
get todayTimes() {
|
||||
if (this.futureTimes.length === 0) {
|
||||
return null;
|
||||
}
|
||||
return new PrayerTimes(this.futureTimes[0], () => this.userNow);
|
||||
},
|
||||
|
||||
translate(key, lang) {
|
||||
return translations[key][lang] ?? key
|
||||
}
|
||||
});
|
||||
|
||||
class PrayerTimes {
|
||||
static salaths = ['fajr', 'sunrise', 'dhuhr', 'asr', 'maghrib', 'isha'];
|
||||
static translations = {
|
||||
fajr: {tr: 'İmsak', de: 'Frühgebet', ar: 'صلاة الفجر'},
|
||||
sunrise: {tr: 'Güneş', de: 'Sonnenaufgang', ar: 'الشروق'},
|
||||
dhuhr: {tr: 'Öğle', de: 'Mittagsgebet', ar: 'صلاة الظهر'},
|
||||
asr: {tr: 'İkindi', de: 'Nachmittagsgebet', ar: 'صلاة العصر'},
|
||||
maghrib: {tr: 'Akşam', de: 'Abendgebet', ar: 'صلاة المغرب'},
|
||||
isha: {tr: 'Yatsı', de: 'Nachtgebet', ar: 'صلاة العشاء'},
|
||||
}
|
||||
|
||||
constructor({date, ...rest}, clock = () => new Date()) {
|
||||
this.date = date;
|
||||
this.clock = clock
|
||||
this.salathTimes = rest
|
||||
}
|
||||
|
||||
get times() {
|
||||
const now = this.clock()
|
||||
return PrayerTimes.salaths.map(k => {
|
||||
// "2023-03-05T00:00:00Z"
|
||||
const startsAt = new Date(this.date.replace('T00:00', `T${this.salathTimes[k]}`).replace(/Z$/, ''));
|
||||
|
||||
return {
|
||||
salath: k,
|
||||
name: lang => PrayerTimes.translations[k][lang] ?? '??',
|
||||
startsAt,
|
||||
timeLocal: this.salathTimes[k],
|
||||
get untilSeconds() {
|
||||
let untilSeconds = (startsAt - now) / 1000;
|
||||
return now > startsAt ? 0 : untilSeconds;
|
||||
},
|
||||
get untilHuman() {
|
||||
return formatDuration(this.untilSeconds)
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
get currentSalath() {
|
||||
let current = this.times.filter(it => it.untilSeconds === 0).at(-1);
|
||||
if (current === undefined) {
|
||||
// we're in isha -> today's fajr is almost the same as tomorrows
|
||||
const prevDay = new Date(this.date);
|
||||
prevDay.setDate(prevDay.getDate() - 1);
|
||||
|
||||
current = new PrayerTimes({date: prevDay.toISOString(), ...this.salathTimes}, this.clock).times.at(-1);
|
||||
}
|
||||
return current
|
||||
}
|
||||
|
||||
get nextSalath() {
|
||||
let next = this.times
|
||||
.filter(it => it.untilSeconds > 0)[0]
|
||||
if (next === undefined) {
|
||||
// we're in isha -> today's fajr is almost the same as tomorrows
|
||||
const nextDay = new Date(this.date);
|
||||
nextDay.setDate(nextDay.getDate() + 1);
|
||||
|
||||
next = new PrayerTimes({date: nextDay.toISOString(), ...this.salathTimes}, this.clock).times[0];
|
||||
}
|
||||
|
||||
return {
|
||||
...next,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} seconds
|
||||
* @return {string}
|
||||
* */
|
||||
function formatDuration(seconds) {
|
||||
const d = new Date(0, 0, 0, 0, 0, seconds);
|
||||
return formatTime(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Date} then
|
||||
* @return {string}
|
||||
* */
|
||||
function formatTime(then) {
|
||||
return new Intl.DateTimeFormat(navigator.language, {
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
second: "numeric"
|
||||
}).format(then);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Date} then
|
||||
* @return {string}
|
||||
* */
|
||||
function formatDate(then) {
|
||||
return new Intl.DateTimeFormat(navigator.language, {
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit"
|
||||
}).format(then);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Date} then
|
||||
* @return {string}
|
||||
* */
|
||||
function formatDateHijri(then) {
|
||||
return new Intl.DateTimeFormat("en-u-ca-islamic-umalqura-nu-latn", {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
}).format(then);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} url
|
||||
* @param {RequestInit} req
|
||||
* */
|
||||
async function fetchJSON(url, req = {}) {
|
||||
const res = await fetch(url, {
|
||||
...req,
|
||||
})
|
||||
return res.json()
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Promise<GeolocationCoordinates>}
|
||||
* */
|
||||
function getUserLocation() {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!navigator.geolocation) {
|
||||
reject("Geolocation is not supported by this browser.");
|
||||
return;
|
||||
}
|
||||
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
(position) => resolve(position.coords),
|
||||
(error) => reject(error.message)
|
||||
);
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user