68 lines
1.4 KiB
Vue
68 lines
1.4 KiB
Vue
<template>
|
|
<slot />
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { Observable, of, tap } from 'rxjs';
|
|
|
|
const props = defineProps({
|
|
name: {
|
|
required: true,
|
|
type: String,
|
|
},
|
|
callback: {
|
|
required: true,
|
|
type: Function,
|
|
},
|
|
lifetime: {
|
|
default: 1000 * 60 * 60, // one hour
|
|
required: false,
|
|
type: Number,
|
|
},
|
|
alreadyKnownData: {
|
|
default: null,
|
|
type: Object,
|
|
},
|
|
});
|
|
|
|
const emits = defineEmits(['cached']);
|
|
|
|
const isDataOutdated = (name: string): boolean => {
|
|
const lastUpdated: number = +localStorage.getItem(name + '-timestamp');
|
|
const elapsedTime: number = Date.now() - lastUpdated;
|
|
return elapsedTime > props.lifetime;
|
|
};
|
|
|
|
const storeInCache = (
|
|
callback: Function,
|
|
data: any,
|
|
name: string,
|
|
): Observable<any> => {
|
|
let response: Observable<any> = data ? of(data) : callback();
|
|
return response.pipe(
|
|
tap((response) => {
|
|
localStorage.setItem(name, JSON.stringify(response));
|
|
localStorage.setItem(name + '-timestamp', `${Date.now()}`);
|
|
}),
|
|
);
|
|
};
|
|
|
|
if (isDataOutdated(props.name)) {
|
|
emits(
|
|
'cached',
|
|
storeInCache(props.callback, props.alreadyKnownData, props.name),
|
|
);
|
|
} else {
|
|
let data = localStorage.getItem(props.name);
|
|
try {
|
|
emits('cached', of(JSON.parse(data)));
|
|
} catch (err) {
|
|
console.error(`Could not parse data found in cache: ${err}`);
|
|
emits(
|
|
'cached',
|
|
storeInCache(props.callback, props.alreadyKnownData, props.name),
|
|
);
|
|
}
|
|
}
|
|
</script>
|