diff --git a/uniquely/flight-finder-pwa/l10n/fa-IR.json b/uniquely/flight-finder-pwa/l10n/fa-IR.json index a1f728707..6130bb2d3 100644 --- a/uniquely/flight-finder-pwa/l10n/fa-IR.json +++ b/uniquely/flight-finder-pwa/l10n/fa-IR.json @@ -5,7 +5,7 @@ "flight_finder": "پرواز یاب", "search_list": "لیست جستجو", - "seconds_ago": "ثانیه پیش", + "minutes_ago": "دقیقه پیش", "origin": "مبدا", "destination": "مقصد", "confirm": "تایید", diff --git a/uniquely/flight-finder-pwa/src/component/job-add-form.ts b/uniquely/flight-finder-pwa/src/component/job-add-form.ts index 5c006339b..0541349e7 100644 --- a/uniquely/flight-finder-pwa/src/component/job-add-form.ts +++ b/uniquely/flight-finder-pwa/src/component/job-add-form.ts @@ -99,7 +99,7 @@ export class JobAddForm extends AlwatrElement { ${l10n.localize('origin')} diff --git a/uniquely/flight-finder-pwa/src/component/job-item.ts b/uniquely/flight-finder-pwa/src/component/job-item.ts index 67fc3322e..3296b826d 100644 --- a/uniquely/flight-finder-pwa/src/component/job-item.ts +++ b/uniquely/flight-finder-pwa/src/component/job-item.ts @@ -79,6 +79,11 @@ export class JobItem extends AlwatrElement { .job .job__subtitle .job__subtitle-price { color: var(--ion-color-base); } + + ion-item-options { + -ms-flex-pack: start; + justify-content: flex-start; + } `, ]; diff --git a/uniquely/flight-finder-pwa/src/component/page-flight-finder.ts b/uniquely/flight-finder-pwa/src/component/page-flight-finder.ts index cb7ef21cf..dfa7ed044 100644 --- a/uniquely/flight-finder-pwa/src/component/page-flight-finder.ts +++ b/uniquely/flight-finder-pwa/src/component/page-flight-finder.ts @@ -3,7 +3,7 @@ import {l10n} from '@alwatr/i18n'; import {SignalInterface} from '@alwatr/signal'; import {modalController} from '@ionic/core'; import {css, html} from 'lit'; -import {customElement} from 'lit/decorators.js'; +import {customElement, query} from 'lit/decorators.js'; import {map} from 'lit/directives/map.js'; import ionNormalize from '../style/ionic.normalize.js'; @@ -42,6 +42,11 @@ export class PageFlightFinder extends AlwatrElement { justify-content: center; } + #timer { + display: inline-block; + min-width: 23px; + } + .version { direction: ltr; margin: 0 16px 8px; @@ -50,11 +55,27 @@ export class PageFlightFinder extends AlwatrElement { `, ]; - private __jobList: Array = []; - - static jobListSignal = new SignalInterface('job-list'); + static jobDocumentStorageSignal = new SignalInterface('job-document-storage'); static jobAddSignal = new SignalInterface('job-add'); + private __jobList?: Array; + private __lastUpdate = 0; + @query('#timer') protected _timer?: HTMLSpanElement; + + constructor() { + super(); + this.__updateTimer = this.__updateTimer.bind(this); + } + + private __updateTimer(): void { + const timer = this._timer; + if (timer == null || this.__lastUpdate === 0) return; + + const time = Math.floor((Date.now() - this.__lastUpdate) / 6_000) / 10; + + timer.innerText = l10n.formatNumber(time); + } + override connectedCallback(): void { super.connectedCallback(); @@ -62,10 +83,13 @@ export class PageFlightFinder extends AlwatrElement { this.requestUpdate(); }); - PageFlightFinder.jobListSignal.addListener((jobList) => { - this.__jobList = jobList; + PageFlightFinder.jobDocumentStorageSignal.addListener((jobList) => { + this.__jobList = Object.values(jobList.data); + this.__lastUpdate = jobList.meta.lastUpdated; this.requestUpdate(); }); + + setInterval(this.__updateTimer, 3_000); } override render(): TemplateResult { return html` @@ -84,7 +108,7 @@ export class PageFlightFinder extends AlwatrElement { -
v${Alwatr.version}-prv3
+
v${Alwatr.version}-prv4
`; } @@ -94,7 +118,7 @@ export class PageFlightFinder extends AlwatrElement { ${l10n.localize('search_list')} - ۵ ${l10n.localize('seconds_ago')} + - ${l10n.localize('minutes_ago')} @@ -113,7 +137,6 @@ export class PageFlightFinder extends AlwatrElement { modal.dismiss(); }); - await modal.present(); } } diff --git a/uniquely/flight-finder-pwa/src/director/index.ts b/uniquely/flight-finder-pwa/src/director/index.ts index 884183416..aab96cb94 100644 --- a/uniquely/flight-finder-pwa/src/director/index.ts +++ b/uniquely/flight-finder-pwa/src/director/index.ts @@ -1,4 +1,4 @@ -import './job-add'; -import './job-delete'; -import './job-list.js'; +import './job-add.js'; +import './job-delete.js'; +import './job-document-storage.js'; import './toast.js'; diff --git a/uniquely/flight-finder-pwa/src/director/job-add.ts b/uniquely/flight-finder-pwa/src/director/job-add.ts index 43c4eae20..bb3904c77 100644 --- a/uniquely/flight-finder-pwa/src/director/job-add.ts +++ b/uniquely/flight-finder-pwa/src/director/job-add.ts @@ -1,7 +1,7 @@ import {fetch} from '@alwatr/fetch'; import {SignalInterface} from '@alwatr/signal'; -import {jobListSignal} from './job-list.js'; +import {jobDocumentStorageSignal} from './job-document-storage.js'; import {showToastSignal} from './toast.js'; import type {Job} from '../type.js'; @@ -34,5 +34,5 @@ jobAddSignal.addListener(async (job) => { }); } - jobListSignal.request(null); + jobDocumentStorageSignal.request(null); }); diff --git a/uniquely/flight-finder-pwa/src/director/job-delete.ts b/uniquely/flight-finder-pwa/src/director/job-delete.ts index 6c98da671..89ce99f2e 100644 --- a/uniquely/flight-finder-pwa/src/director/job-delete.ts +++ b/uniquely/flight-finder-pwa/src/director/job-delete.ts @@ -1,7 +1,7 @@ import {fetch} from '@alwatr/fetch'; import {SignalInterface} from '@alwatr/signal'; -import {jobListSignal} from './job-list.js'; +import {jobDocumentStorageSignal} from './job-document-storage.js'; import {showToastSignal} from './toast.js'; import type {AlwatrServiceResponse} from '@alwatr/fetch'; @@ -33,5 +33,5 @@ jobDeleteSignal.addListener(async (id) => { }); } - jobListSignal.request(null); + jobDocumentStorageSignal.request(null); }); diff --git a/uniquely/flight-finder-pwa/src/director/job-document-storage.ts b/uniquely/flight-finder-pwa/src/director/job-document-storage.ts new file mode 100644 index 000000000..ccae37e4d --- /dev/null +++ b/uniquely/flight-finder-pwa/src/director/job-document-storage.ts @@ -0,0 +1,40 @@ +import {serviceRequest} from '@alwatr/fetch'; +import {AlwatrDocumentStorage, CacheStrategy} from '@alwatr/fetch/src/type.js'; +import {createLogger} from '@alwatr/logger'; +import {SignalInterface} from '@alwatr/signal'; + +import {showToastSignal} from './toast.js'; + +import type {Job} from '../type.js'; + +export const logger = createLogger('[director/job-document-storage]'); +export const jobDocumentStorageSignal = new SignalInterface('job-document-storage'); + +async function requestJobStorage(cacheStrategy: CacheStrategy): Promise { + logger.logMethod('jobListProvider'); + + try { + jobDocumentStorageSignal.dispatch( + > await serviceRequest({ + url: window.appConfig?.api ? window.appConfig.api + '/job' : '/job', + token: window.appConfig?.token, + cache: 'no-cache', + cacheStrategy, + }), + ); + } + catch (error) { + if ((error as Error).message !== 'fetch_cache_not_found') { + logger.error('jobListProvider', 'fetch_failed', error); + showToastSignal.dispatch({ + message: 'عملیات با خطا رو به رو شد', + }); + } + } +} + +jobDocumentStorageSignal.setProvider(() => requestJobStorage('network_first')); + +requestJobStorage('cache_only').then(() => requestJobStorage('network_first')); + +setInterval(() => jobDocumentStorageSignal.request(null), 60_000); diff --git a/uniquely/flight-finder-pwa/src/director/job-list.ts b/uniquely/flight-finder-pwa/src/director/job-list.ts deleted file mode 100644 index a9dd2316a..000000000 --- a/uniquely/flight-finder-pwa/src/director/job-list.ts +++ /dev/null @@ -1,48 +0,0 @@ -import {fetch} from '@alwatr/fetch'; -import {SignalInterface} from '@alwatr/signal'; - -import {showToastSignal} from './toast.js'; - -import type {Job} from '../type.js'; -import type {AlwatrServiceResponse} from '@alwatr/fetch'; - -export const jobListSignal = new SignalInterface('job-list'); - -async function _dispatchJobList(response: Response): Promise { - if (response.ok !== true) { - throw new Error('fetch_failed'); - } - - const responseData = (await response.json()) as AlwatrServiceResponse>; - - if (responseData.ok !== true) { - throw new Error('fetch_failed'); - } - - jobListSignal.dispatch(Object.values(responseData.data)); -} - -jobListSignal.setProvider(async () => { - try { - const response = await fetch({ - url: window.appConfig?.api ? window.appConfig.api + '/job' : '/job', - token: window.appConfig?.token, - cacheStrategy: 'stale_while_revalidate', - revalidateCallback(response) { - _dispatchJobList(response); - }, - cache: 'no-cache', - }); - - await _dispatchJobList(response); - } - catch (error) { - showToastSignal.dispatch({ - message: 'عملیات با خطا رو به رو شد', - }); - } - return; -}); - -jobListSignal.request(null); -setInterval(()=>jobListSignal.request(null), 60_000); diff --git a/uniquely/flight-finder-pwa/src/type.ts b/uniquely/flight-finder-pwa/src/type.ts index 644a3cd91..2d2feea29 100644 --- a/uniquely/flight-finder-pwa/src/type.ts +++ b/uniquely/flight-finder-pwa/src/type.ts @@ -1,4 +1,4 @@ -import type {AlwatrDocumentObject} from '@alwatr/fetch'; +import type {AlwatrDocumentObject, AlwatrDocumentStorage} from '@alwatr/fetch/type.js'; import type {ToastOptions} from '@ionic/core'; declare global { @@ -8,11 +8,11 @@ declare global { interface AlwatrSignals { readonly 'job-add': Pick; readonly 'job-delete': string; - readonly 'job-list': Array; + readonly 'job-document-storage': AlwatrDocumentStorage; readonly toast: Partial & {message: string}; } interface AlwatrRequestSignals { - readonly 'job-list': null; + readonly 'job-document-storage': null; } } @@ -42,8 +42,8 @@ export type JobResult = { price: number; time: string; seatCount: number; - airline: string, - airplane: string, - flightId: string, - arrivalTime: string, + airline: string; + airplane: string; + flightId: string; + arrivalTime: string; };