commit 5733299ea999eb0964b24dedf8d7eeb88472371a
parent d199240e69d2638fa84f28db8f42b57c59598b4e
Author: Yureka <yuka@yuka.dev>
Date: Wed, 18 Aug 2021 17:04:59 +0200
parent d199240e69d2638fa84f28db8f42b57c59598b4e
Author: Yureka <yuka@yuka.dev>
Date: Wed, 18 Aug 2021 17:04:59 +0200
client cleanup
8 files changed, 194 insertions(+), 176 deletions(-)
M
|
73
+++++++++++++++++++++++++++++++++++++++++++++----------------------------
M
|
101
+++++++++++++++++++------------------------------------------------------------
diff --git a/client/src/app_functions.js b/client/src/app_functions.js @@ -1,25 +1,26 @@ -import { dbReady, getSettings, addHistoryEntry, getJourneysHistory } from './dataStorage.js'; -import { get } from './api.js'; +import { db } from './dataStorage.js'; +import { settings, subscribeSettings } from './settings.js'; +import { get, post } from './api.js'; import { showModal } from './overlays.js'; import { languages } from './languages.js'; import { html } from 'lit-html'; import { formatDateTime, getFrom, getTo } from './helpers.js'; let ds100 = {}; -// we don't want to pass these around all the time -let settings; -export const applySettings = async newSettings => { - settings = newSettings; +subscribeSettings(async () => { if (settings.showRIL100Names) await loadDS100(); -}; +}); + +export const getJourneysHistory = () => db.getAll('journeysHistory'); + +export const addHistoryEntry = newEntry => db.put('journeysHistory', newEntry); -export const addJourneys = async data => { +const addJourneys = async data => { if (!data) return false; ConsoleLog(data); - const db = await dbReady; await db.put('journeys', data); //const lastHistoryEntry = (await getJourneysHistory()).slice(-1); @@ -39,20 +40,16 @@ export const addJourneys = async data => { //} }; -export const getJourneys = async slug => { - if (!slug) return; - - const db = await dbReady; - let data = await db.get('journeys', slug); - if (!data) { - data = await get("savedJourneys/" + slug, { - stopovers: true, - polylines: settings.showMap || false, - tickets: settings.showPrices || false, - }); - await addJourneys(data); - } +const mkParams = () => { + return { + stopovers: true, + polylines: settings.showMap || false, + tickets: settings.showPrices || false, + language: settings.language, + }; +}; +const processData = data => { for (let journey of data.journeys) { for (let leg of journey.legs) { if (leg.plannedDeparture) leg.plannedDeparture = new Date(leg.plannedDeparture); @@ -68,16 +65,36 @@ export const getJourneys = async slug => { } } return data; +} + +export const getJourneys = async slug => { + if (!slug) return; + + let data = await db.get('journeys', slug); + if (!data) { + data = await get(`savedJourneys/${slug}`, mkParams()); + await addJourneys(data); + } + + return processData(data); +}; + +export const getMoreJourneys = async (slug, mode, hideLoader) => { + const data = await post(`savedJourneys/${slug}/${mode}`, mkParams(), hideLoader); + await addJourneys(data); + return processData(data); }; export const refreshJourneys = async (reqId, hideLoader) => { - const data = await get("savedJourneys/"+reqId, { - stopovers: true, - polylines: settings.showMap || false, - tickets: settings.showPrices || false, - }, hideLoader); + const data = await get(`savedJourneys/${reqId}`, mkParams(), hideLoader); await addJourneys(data); - return data; + return processData(data); +}; + +export const newJourneys = async (params, hideLoader) => { + const data = await post(`savedJourneys`, { ...mkParams(), ...params }, hideLoader); + await addJourneys(data); + return processData(data); }; export const t = (key, ...params) => {
diff --git a/client/src/dataStorage.js b/client/src/dataStorage.js @@ -3,82 +3,29 @@ import { openDB, deleteDB } from 'idb'; export const devMode = false; const dbName = devMode ? 'trainsearch_dev' : 'trainsearch'; -const getDefaultLanguage = () => { - const userLang = navigator.language || navigator.userLanguage; - if (['en', 'de'].includes(userLang)) return userLang; - return 'en'; +export let db; + +export const initDataStorage = async () => { + db = await openDB(dbName, 1, { + upgrade: (db, oldVersion, newVersion, transaction) => { + console.log(`upgrading database from ${oldVersion} to ${newVersion}`); + switch (oldVersion) { + case 0: + if (!db.objectStoreNames.contains('journeys')) + db.createObjectStore('journeys', {keyPath: 'slug'}); + if (!db.objectStoreNames.contains('journeysHistory')) + db.createObjectStore('journeysHistory', {autoIncrement: true}); + if (!db.objectStoreNames.contains('settings')) + db.createObjectStore('settings'); + case 1: + //... add migrations for 1->2 here + } + }, + blocking: async () => { + db.close(); + location.reload(); + }, + }); }; -const defaultSettings = { - provider: 'DB', - products: { - "nationalExpress": true, - "national": true, - "regionalExp": true, - "regional": true, - "suburban": true, - "bus": true, - "ferry": true, - "subway": true, - "tram": true, - "taxi": true - }, - accessibility: 'none', - advancedSelection: false, - showRIL100Names: false, - writeDebugLog: false, - language: getDefaultLanguage(), - travelynx: false, - journeysViewMode: 'canvas', - showMap: false, - showPrices: false, -}; - -export const dbReady = openDB(dbName, 1, { - upgrade: (db, oldVersion, newVersion, transaction) => { - console.log(`upgrading database from ${oldVersion} to ${newVersion}`); - switch (oldVersion) { - case 0: - if (!db.objectStoreNames.contains('journeys')) - db.createObjectStore('journeys', {keyPath: 'slug'}); - if (!db.objectStoreNames.contains('journeysHistory')) - db.createObjectStore('journeysHistory', {autoIncrement: true}); - if (!db.objectStoreNames.contains('settings')) - db.createObjectStore('settings'); - case 1: - //... add migrations for 1->2 here - } - }, - blocking: async () => { - const db = await dbReady; - db.close(); - location.reload(); - }, -}); - -export const getSettings = async () => { - const db = await dbReady; - return (await db.get('settings', 'settings')) || defaultSettings; -}; - -export const setSettings = async newSettings => { - const db = await dbReady; - await db.put('settings', newSettings, 'settings'); -}; - -export const modifySettings = async callback => { - const db = await dbReady; - const tx = db.transaction('settings', 'readwrite'); - const settings = (await tx.store.get('settings')) || defaultSettings; - const newSettings = callback(settings); - await tx.store.put(newSettings, 'settings'); - await tx.done; -}; - -export const getJourneysHistory = () => dbReady.then(db => db.getAll('journeysHistory')); - -export const addHistoryEntry = newEntry => dbReady.then(db => db.put('journeysHistory', newEntry)); - -export const clearDataStorage = () => { - deleteDB(dbName); -}; +export const clearDataStorage = () => deleteDB(dbName);
diff --git a/client/src/journeyView.js b/client/src/journeyView.js @@ -1,6 +1,6 @@ -import { getSettings } from './dataStorage.js'; +import { settings } from './settings.js'; import { showDiv, hideDiv, ElementById, formatDateTime, formatDuration } from './helpers.js'; -import { ConsoleLog, parseName, ds100Names, t, timeTemplate, getJourneys, addJourneys, refreshJourneys } from './app_functions.js'; +import { ConsoleLog, parseName, ds100Names, t, timeTemplate, getJourneys, refreshJourneys } from './app_functions.js'; import { showModal } from './overlays.js'; import { get } from './api.js'; import { go } from './router.js'; @@ -27,7 +27,7 @@ const getAdditionalName = (line) => { return null; }; -const travelynxTemplate = (settings, element) => { +const travelynxTemplate = (element) => { if (settings.travelynx && element.line && element.line.mode === 'train') { let trainName = getAdditionalName(element.line) || element.line.name; @@ -44,7 +44,7 @@ const remarksTemplate = ([type, remarks]) => !!remarks.length ? html` <a class="link icon-${type}" @click=${() => showRemarksModal(type, remarks)}></a> ` : ''; -const legTemplate = (settings) => (leg) => { +const legTemplate = leg => { const allRemarks = leg.remarks || []; const remarks = { "status": allRemarks.filter(r => r.type === 'status'), @@ -77,7 +77,7 @@ const legTemplate = (settings) => (leg) => { `} ${leg.cancelled ? html`<b class="cancelled-text">${t('cancelled-ride')}</b>` : ''} ${Object.entries(remarks).map(remarksTemplate)} - ${travelynxTemplate(settings, leg)}</span> + ${travelynxTemplate(leg)}</span> </td> </tr> <tr> @@ -122,7 +122,7 @@ const legTemplate = (settings) => (leg) => { `; }; -const journeyTemplate = (settings, data, requestId, journeyId) => { +const journeyTemplate = (data, requestId, journeyId) => { const duration = data.legs[data.legs.length - 1].arrival - data.legs[0].departure; const legs = []; @@ -163,7 +163,7 @@ const journeyTemplate = (settings, data, requestId, journeyId) => { <a class="reload icon-reload" title="{{LABEL_RELOAD}}" @click=${() => refreshJourneyView(requestId, journeyId)}>{{LABEL_RELOAD}}</a> </header> - ${legs.map(legTemplate(settings))} + ${legs.map(legTemplate)} </div> `; }; @@ -193,7 +193,6 @@ const stopPlatformTemplate = (data) => { }; export const journeyView = async (match) => { - const settings = await getSettings(); const reqId = match[0]; const journeyId = Number(match[1]); @@ -202,7 +201,7 @@ export const journeyView = async (match) => { const data = all.journeys[journeyId + all.indexOffset]; ConsoleLog(data); - render(journeyTemplate(settings, data, reqId, journeyId), ElementById('content')); + render(journeyTemplate(data, reqId, journeyId), ElementById('content')); /*const history_id = dataStorage.journeysHistory.findIndex(obj => obj.reqId === reqId);
diff --git a/client/src/journeysView.js b/client/src/journeysView.js @@ -1,13 +1,13 @@ import { showDiv, hideDiv, ElementById, formatDuration, formatFromTo, getFrom, getTo, padZeros } from './helpers.js'; -import { parseName, ConsoleLog, t, timeTemplate, getJourneys, addJourneys } from './app_functions.js'; -import { getSettings, modifySettings } from './dataStorage.js'; +import { parseName, ConsoleLog, t, timeTemplate, getJourneys, getMoreJourneys } from './app_functions.js'; +import { settings, modifySettings } from './settings.js'; import { setupCanvas } from './canvas.js'; import { post } from './api.js'; import { go } from './router.js'; import { html, render } from 'lit-html'; import { showAlertModal } from './overlays.js'; -const journeysTemplate = (settings, data) => html` +const journeysTemplate = (data) => html` <div class="journeys"> <header id="header"> <a class="back icon-back" href="#/" title="${t('back')}">${t('back')}</a> @@ -62,7 +62,7 @@ const journeysTemplate = (settings, data) => html` </tr> </thead> <tbody> - ${Object.entries(data.journeys).map(([key, val]) => journeyOverviewTemplate(settings, val, data.slug, key - data.indexOffset))} + ${Object.entries(data.journeys).map(([key, val]) => journeyOverviewTemplate(val, data.slug, key - data.indexOffset))} </tbody> </table> </div> @@ -72,7 +72,7 @@ const journeysTemplate = (settings, data) => html` </div> `; -const journeyOverviewTemplate = (settings, entry, slug, key) => { +const journeyOverviewTemplate = (entry, slug, key) => { let firstLeg = entry.legs[0]; let lastLeg = entry.legs[entry.legs.length - 1]; let changes = 0; @@ -134,10 +134,9 @@ const formatPrice = price => { export const journeysView = async (match, isUpdate) => { const slug = match[0]; - const settings = await getSettings(); const data = await getJourneys(slug); - render(journeysTemplate(settings, data), ElementById('content')); + render(journeysTemplate(data), ElementById('content')); if (settings.journeysViewMode === 'canvas') setupCanvas(data, isUpdate); if (settings.journeysViewMode === 'map') { @@ -158,12 +157,6 @@ const changeMode = (mode) => { }; export const moreJourneys = async (slug, mode) => { - const settings = await getSettings(); - const data = await post(`savedJourneys/${slug}/${mode}`, { - stopovers: true, - polylines: settings.showMap || false, - tickets: settings.showPrices || false, - }); - await addJourneys(data); + await getMoreJourneys(slug, mode); journeysView([slug], true); };
diff --git a/client/src/main.js b/client/src/main.js @@ -2,13 +2,14 @@ import { route, go, start } from './router.js'; import { searchView } from './searchView.js'; import { journeysView } from './journeysView.js'; import { journeyView } from './journeyView.js'; -import { applySettings } from './app_functions.js'; -import { getSettings } from './dataStorage.js'; +import { initSettings } from './settings.js'; +import { initDataStorage } from './dataStorage.js'; import { showDiv, hideDiv, ElementById } from './helpers.js'; (async () => { - const settings = await getSettings(); - await applySettings(settings); + // read settings from indexeddb + await initDataStorage(); + await initSettings(); route(/^\/$/, searchView); route(/^\/([a-zA-Z0-9]+)$/, journeysView);
diff --git a/client/src/searchView.js b/client/src/searchView.js @@ -1,13 +1,13 @@ import { showDiv, ElementById, padZeros, isValidDate, formatFromTo } from './helpers.js'; -import { parseName, ConsoleLog, t, loadDS100, getJourneys, addJourneys } from './app_functions.js'; -import { getSettings, modifySettings, getJourneysHistory } from './dataStorage.js'; +import { parseName, ConsoleLog, t, loadDS100, getJourneys, getJourneysHistory, newJourneys } from './app_functions.js'; +import { modifySettings, settings } from './settings.js'; import { get, post } from './api.js'; import { go } from './router.js'; import { html, render } from 'lit-html'; import { showAlertModal, showSelectModal, showLoader, hideOverlay} from './overlays.js'; import { showSettings } from './settingsView.js'; -let suggestionsCache = { +const suggestions = { from: {}, via: {}, to: {}, @@ -21,7 +21,7 @@ let isArrValue = false; let dateValue = currDate.getFullYear()+'-'+padZeros(currDate.getMonth()+1)+'-'+padZeros(currDate.getDate());; let timeValue = padZeros(currDate.getHours())+':'+padZeros(currDate.getMinutes()); -const searchTemplate = (settings, journeysHistory) => html` +const searchTemplate = (journeysHistory) => html` <div id="searchView" class="center"> <form class="search" onsubmit="return false;"> <div class="title"> @@ -167,9 +167,8 @@ const journeysHistoryAction = (journeysHistory, element) => { }; export const searchView = async () => { - const settings = await getSettings(); const journeysHistory = (await getJourneysHistory()).slice().reverse(); - render(searchTemplate(settings, journeysHistory), ElementById('content')); + render(searchTemplate(journeysHistory), ElementById('content')); ElementById('from').focus(); @@ -186,7 +185,6 @@ export const search = async (requestId) => { settings.accessibility = document.querySelector('input[name="accessibility"]:checked').value; return settings; }); - const settings = await getSettings(); const provider = settings.provider; let isDep = !ElementById('isarr').checked; @@ -223,45 +221,45 @@ export const search = async (requestId) => { time = padZeros(currDate.getHours())+':'+padZeros(currDate.getMinutes()); } - if (Object.entries(suggestionsCache.from).length !== 0) { - from = suggestionsCache.from; + if (Object.entries(suggestions.from).length !== 0) { + from = suggestions.from; } else { - let suggestions = await get("locations", {"query": fromValue, "results": 1}, true); + let data = await get("locations", {"query": fromValue, "results": 1}, true); - if (!suggestions[0]) { + if (!data[0]) { showAlertModal("Invalid From"); return; } - from = suggestions[0] + from = data[0] } if (ElementById('via').value == "") { via = null; - } else if (Object.entries(suggestionsCache.via).length !== 0) { - via = suggestionsCache.via; + } else if (Object.entries(suggestions.via).length !== 0) { + via = suggestions.via; } else { - let suggestions = await get("locations", {"query": viaValue, "results": 1}, true); + let data = await get("locations", {"query": viaValue, "results": 1}, true); - if (!suggestions[0]) { + if (!data[0]) { showAlertModal("Invalid Via"); return; } - via = suggestions[0] + via = data[0] } - if (Object.entries(suggestionsCache.to).length !== 0) { - to = suggestionsCache.to; + if (Object.entries(suggestions.to).length !== 0) { + to = suggestions.to; } else { - let suggestions = await get("locations", {"query": toValue, "results": 1}, true); + let data = await get("locations", {"query": toValue, "results": 1}, true); - if (!suggestions[0]) { + if (!data[0]) { showAlertModal("Invalid To"); return; } - to = suggestions[0] + to = data[0] } const split_date = date.split('-'); @@ -274,9 +272,6 @@ export const search = async (requestId) => { let params = { from: formatFromTo(from), to: formatFromTo(to), - stopovers: true, - polylines: settings.showMap || false, - tickets: settings.showPrices || false, results: 6, //"accessibility": settings.accessibility, ...settings.products, @@ -289,15 +284,14 @@ export const search = async (requestId) => { else params.arrival = timestamp; - const data = await post("savedJourneys", params); - addJourneys(data); - go('/' + data.slug); + const { slug } = await newJourneys(params); + go('/' + slug); return false; }; -const suggestionsTemplate = (suggestions, inputId) => html` +const suggestionsTemplate = (data, inputId) => html` <div class="suggestionsbox" @mouseover=${mouseOverSuggestions} @mouseout=${stopMouseOverSuggestions}> - ${suggestions.map(element => html` + ${data.map(element => html` <p class="suggestion" @click=${() => setSuggestion(encodeURI(JSON.stringify(element)), inputId)}>${parseName(element)}</p> `)} </div> @@ -305,10 +299,10 @@ const suggestionsTemplate = (suggestions, inputId) => html` const loadSuggestions = async (e, input) => { const val = e.target.value; - suggestionsCache[e.target.id] = {}; - const suggestions = val ? await get("locations", {"query": val, "results": 10}, true) : []; + suggestions[e.target.id] = {}; + const data = val ? await get("locations", {"query": val, "results": 10}, true) : []; const suggestionsEl = ElementById(e.target.id+'Suggestions'); - render(suggestionsTemplate(suggestions, e.target.id), suggestionsEl); + render(suggestionsTemplate(data, e.target.id), suggestionsEl); }; export const setSuggestion = (data, inputId) => { @@ -316,7 +310,7 @@ export const setSuggestion = (data, inputId) => { data = JSON.parse(decodeURI(data)); } - suggestionsCache[inputId] = data; + suggestions[inputId] = data; ElementById(inputId).value = parseName(data); if (inputId === 'from') { @@ -332,7 +326,7 @@ export const setSuggestion = (data, inputId) => { }; export const swapFromTo = () => { - suggestionsCache.from = [suggestionsCache.to, suggestionsCache.to = suggestionsCache.from][0]; + suggestions.from = [suggestions.to, suggestions.to = suggestions.from][0]; let from = ElementById('from'); let to = ElementById('to');
diff --git a/client/src/settings.js b/client/src/settings.js @@ -0,0 +1,55 @@ +import { db } from './dataStorage.js'; + +const getDefaultLanguage = () => { + const userLang = navigator.language || navigator.userLanguage; + if (['en', 'de'].includes(userLang)) return userLang; + return 'en'; +}; + +const defaultSettings = { + provider: 'DB', + products: { + "nationalExpress": true, + "national": true, + "regionalExp": true, + "regional": true, + "suburban": true, + "bus": true, + "ferry": true, + "subway": true, + "tram": true, + "taxi": true + }, + accessibility: 'none', + advancedSelection: false, + showRIL100Names: false, + writeDebugLog: false, + language: getDefaultLanguage(), + travelynx: false, + journeysViewMode: 'canvas', + showMap: false, + showPrices: false, +}; + +const subscribers = []; + +export let settings; + +export const subscribeSettings = cb => { + subscribers.push(cb); +}; + +export const initSettings = async () => { + settings = (await db.get('settings', 'settings')) || defaultSettings; + for (let cb of subscribers) await cb(); +}; + +export const modifySettings = async callback => { + const tx = db.transaction('settings', 'readwrite'); + const newSettings = callback(JSON.parse(JSON.stringify(settings))); + await tx.store.put(newSettings, 'settings'); + await tx.done; + Object.freeze(newSettings); + settings = newSettings; + for (let cb of subscribers) await cb(); +};
diff --git a/client/src/settingsView.js b/client/src/settingsView.js @@ -1,16 +1,16 @@ -import { getSettings, modifySettings, clearDataStorage } from './dataStorage.js'; +import { db, clearDataStorage } from './dataStorage.js'; +import { modifySettings, settings } from './settings.js'; import { showModal } from './overlays.js'; import { hideDiv, ElementById } from './helpers.js'; -import { ConsoleLog, t, applySettings } from './app_functions.js'; +import { ConsoleLog, t } from './app_functions.js'; import { html, render } from 'lit-html'; import { searchView } from './searchView.js'; export const showSettings = async () => { - const settings = await getSettings(); - showModal(t('settings'), settingsTemplate(settings)) + showModal(t('settings'), settingsTemplate()) }; -const settingsTemplate = settings => html` +const settingsTemplate = () => html` <div id="settingsView"> <b>${t('options')}:</b><br> <label><input type="checkbox" ?checked=${settings.showRIL100Names} id="ril100"> ${t('showds100')}</label><br> @@ -44,17 +44,29 @@ const newAll = () => { }; const saveSettings = async () => { + let clearJourneys = false; + let clearJourneysHistory = false; await modifySettings(settings => { - settings.language = document.querySelector('input[name="language"]:checked').value; settings.showRIL100Names = ElementById('ril100').checked; settings.writeDebugLog = ElementById('debug-messages').checked; settings.travelynx = ElementById('travelynx').checked; settings.advancedSelection = ElementById('advancedSelection').checked; - settings.showMap = ElementById('feature-map').checked; - settings.showPrices = ElementById('feature-prices').checked; + + const language = document.querySelector('input[name="language"]:checked').value; + if (settings.language != language) clearJourneys = true; + settings.language = language; + + const showMap = ElementById('feature-map').checked; + if (settings.showMap != showMap) clearJourneys = clearJourneys || showMap; + settings.showMap = showMap; + + const showPrices = ElementById('feature-prices').checked; + if (settings.showPrices != showPrices) clearJourneys = clearJourneys || showPrices; + settings.showPrices = showPrices; + return settings; }); - await applySettings(await getSettings()); + if (clearJourneys) await db.clear('journeys'); searchView(); hideDiv('overlay'); };