mirror of
https://github.com/HSLdevcom/digitransit-ui
synced 2025-07-05 16:30:37 +02:00
329 lines
8.4 KiB
JavaScript
329 lines
8.4 KiB
JavaScript
import Store from 'fluxible/addons/BaseStore';
|
|
import find from 'lodash/find';
|
|
import findIndex from 'lodash/findIndex';
|
|
import isEmpty from 'lodash/isEmpty';
|
|
import { v4 as uuid } from 'uuid';
|
|
import { unixTime } from '../util/timeUtils';
|
|
import {
|
|
clearFavouriteStorage,
|
|
getFavouriteStorage,
|
|
setFavouriteStorage,
|
|
} from './localStorage';
|
|
import {
|
|
deleteFavourites,
|
|
getFavourites,
|
|
updateFavourites,
|
|
} from '../util/apiUtils';
|
|
import {
|
|
mapVehicleRentalFromStore,
|
|
mapVehicleRentalToStore,
|
|
} from '../util/vehicleRentalUtils';
|
|
|
|
// internal data model for vehicle rental stations has changed
|
|
// however, data is stored in old form for compatibility
|
|
function mapFromStore(favourites) {
|
|
return favourites.map(favourite =>
|
|
favourite.type === 'bikeStation'
|
|
? mapVehicleRentalFromStore(favourite)
|
|
: favourite,
|
|
);
|
|
}
|
|
|
|
function mapToStore(favourites) {
|
|
return favourites.map(favourite =>
|
|
favourite.type === 'bikeStation'
|
|
? mapVehicleRentalToStore(favourite)
|
|
: favourite,
|
|
);
|
|
}
|
|
|
|
export default class FavouriteStore extends Store {
|
|
static storeName = 'FavouriteStore';
|
|
|
|
static STATUS_FETCHING_OR_UPDATING = 'fetching';
|
|
|
|
static STATUS_HAS_DATA = 'has-data';
|
|
|
|
static FETCH_FAILED = 'fetch-failed';
|
|
|
|
favourites = [];
|
|
|
|
config = {};
|
|
|
|
status = null;
|
|
|
|
constructor(dispatcher) {
|
|
super(dispatcher);
|
|
this.config = dispatcher.getContext().config;
|
|
if (!this.config.allowLogin) {
|
|
this.favourites = mapFromStore(getFavouriteStorage());
|
|
} else {
|
|
this.status = FavouriteStore.STATUS_FETCHING_OR_UPDATING;
|
|
}
|
|
}
|
|
|
|
fetchComplete() {
|
|
this.status = FavouriteStore.STATUS_HAS_DATA;
|
|
this.emitChange();
|
|
}
|
|
|
|
fetchingOrUpdating() {
|
|
this.status = FavouriteStore.STATUS_FETCHING_OR_UPDATING;
|
|
this.emitChange();
|
|
}
|
|
|
|
fetchFailed() {
|
|
this.status = FavouriteStore.FETCH_FAILED;
|
|
this.emitChange();
|
|
}
|
|
|
|
set(favs) {
|
|
this.favourites = mapFromStore(favs);
|
|
this.fetchComplete();
|
|
}
|
|
|
|
fetchFavourites() {
|
|
this.fetchingOrUpdating();
|
|
getFavourites()
|
|
.then(res => {
|
|
if (this.config.allowFavouritesFromLocalstorage) {
|
|
this.mergeWithLocalstorage(res);
|
|
} else {
|
|
this.set(res);
|
|
}
|
|
})
|
|
.catch(() => {
|
|
if (this.config.allowFavouritesFromLocalstorage) {
|
|
this.set(getFavouriteStorage());
|
|
} else {
|
|
this.fetchFailed();
|
|
}
|
|
});
|
|
}
|
|
|
|
getStatus() {
|
|
return this.status;
|
|
}
|
|
|
|
isFavourite(id, type) {
|
|
for (let i = 0; i < this.favourites.length; i++) {
|
|
const favourite = this.favourites[i];
|
|
const fid = favourite.gtfsId || favourite.gid || favourite.stationId;
|
|
if (favourite.type === type && fid === id) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
clearFavourites() {
|
|
clearFavouriteStorage();
|
|
this.favourites = [];
|
|
this.storeFavourites();
|
|
this.emitChange();
|
|
}
|
|
|
|
getFavourites() {
|
|
return this.favourites;
|
|
}
|
|
|
|
getByGtfsId(gtfsId, type) {
|
|
return find(
|
|
this.favourites,
|
|
favourite => gtfsId === favourite.gtfsId && type === favourite.type,
|
|
);
|
|
}
|
|
|
|
getByStationIdAndNetworks(stationId, network) {
|
|
return find(
|
|
this.favourites,
|
|
favourite =>
|
|
stationId === favourite.stationId && network === favourite.network,
|
|
);
|
|
}
|
|
|
|
getRouteGtfsIds() {
|
|
return this.favourites
|
|
.filter(favourite => favourite.type === 'route')
|
|
.map(favourite => favourite.gtfsId);
|
|
}
|
|
|
|
getStopsAndStations() {
|
|
return this.favourites.filter(
|
|
favourite => favourite.type === 'stop' || favourite.type === 'station',
|
|
);
|
|
}
|
|
|
|
getStops() {
|
|
return this.favourites.filter(favourite => favourite.type === 'stop');
|
|
}
|
|
|
|
getLocations() {
|
|
return this.favourites.filter(favourite => favourite.type === 'place');
|
|
}
|
|
|
|
getVehicleRentalStations() {
|
|
return this.favourites.filter(
|
|
favourite => favourite.type === 'bikeStation',
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Merges array of favourites with favourites from localstorage and returns uniques by favouriteId and gtfsId.
|
|
* If there are duplicates by favouriteId or gtfsId, newer one is saved (by lastUpdated field)
|
|
* @param {array} arrayOfFavourites array of favourites
|
|
*/
|
|
mergeWithLocalstorage(arrayOfFavourites) {
|
|
const storage = getFavouriteStorage();
|
|
if (isEmpty(storage)) {
|
|
this.set(arrayOfFavourites);
|
|
return;
|
|
}
|
|
|
|
updateFavourites(storage)
|
|
.then(res => {
|
|
this.set(res);
|
|
clearFavouriteStorage();
|
|
})
|
|
.catch(() => {
|
|
this.set(arrayOfFavourites);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Saves (or updates) favourite.
|
|
* Triggers onFail callback function when storing favourite fails.
|
|
* Generates or updates lastUpdated epoch and for new favourites,
|
|
* it also generates favouriteId.
|
|
*
|
|
* @param {*} actionData object containing favourite data
|
|
* and on fail callback function under onFail key
|
|
*/
|
|
saveFavourite(actionData) {
|
|
let { ...data } = actionData;
|
|
const { onFail } = actionData;
|
|
if (typeof data !== 'object') {
|
|
onFail();
|
|
throw new Error(`New favourite is not a object:${JSON.stringify(data)}`);
|
|
}
|
|
this.fetchingOrUpdating();
|
|
if (data.type === 'bikeStation') {
|
|
data = mapVehicleRentalToStore(data);
|
|
}
|
|
const newFavourites = mapToStore(this.favourites);
|
|
const editIndex = findIndex(
|
|
newFavourites,
|
|
item => data.favouriteId === item.favouriteId,
|
|
);
|
|
if (editIndex >= 0) {
|
|
newFavourites[editIndex] = {
|
|
...data,
|
|
lastUpdated: unixTime(),
|
|
};
|
|
} else {
|
|
newFavourites.push({
|
|
...data,
|
|
lastUpdated: unixTime(),
|
|
favouriteId: uuid(),
|
|
});
|
|
}
|
|
if (this.config.allowLogin) {
|
|
// Update favourites to backend service
|
|
updateFavourites(newFavourites)
|
|
.then(res => {
|
|
this.set(res);
|
|
})
|
|
.catch(() => {
|
|
onFail();
|
|
if (this.config.allowFavouritesFromLocalstorage) {
|
|
this.set(newFavourites);
|
|
setFavouriteStorage(newFavourites);
|
|
}
|
|
this.fetchComplete();
|
|
});
|
|
} else {
|
|
this.set(newFavourites);
|
|
setFavouriteStorage(newFavourites);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Replaces existing array of favourites with an updated array of favourites.
|
|
*
|
|
* @param {*} actionData object containing array of new favourites
|
|
* and on fail callback function under onFail key
|
|
*/
|
|
updateFavourites(actionData) {
|
|
const { onFail, newFavourites } = actionData;
|
|
if (!Array.isArray(newFavourites)) {
|
|
onFail();
|
|
throw new Error(
|
|
`New favourites is not an array:${JSON.stringify(newFavourites)}`,
|
|
);
|
|
}
|
|
const mapped = mapToStore(newFavourites);
|
|
this.fetchingOrUpdating();
|
|
if (this.config.allowLogin) {
|
|
// Update favourites to backend service
|
|
updateFavourites(mapped)
|
|
.then(res => {
|
|
this.set(res);
|
|
})
|
|
.catch(() => {
|
|
onFail();
|
|
if (this.config.allowFavouritesFromLocalstorage) {
|
|
this.set(mapped);
|
|
setFavouriteStorage(mapped);
|
|
}
|
|
this.fetchComplete();
|
|
});
|
|
} else {
|
|
this.set(mapped);
|
|
setFavouriteStorage(mapped);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Deletes given favourite if one exists in store.
|
|
*
|
|
* @param {*} actionData object containing data for favourite to be deleted
|
|
* and on fail callback function under onFail key
|
|
*/
|
|
deleteFavourite(actionData) {
|
|
const { onFail, ...data } = actionData;
|
|
if (typeof data !== 'object') {
|
|
onFail();
|
|
throw new Error(`Favourite is not an object:${JSON.stringify(data)}`);
|
|
}
|
|
this.fetchingOrUpdating();
|
|
const newFavourites = mapToStore(this.favourites).filter(
|
|
favourite => favourite.favouriteId !== data.favouriteId,
|
|
);
|
|
if (this.config.allowLogin) {
|
|
// Delete favourite from backend service
|
|
deleteFavourites([data.favouriteId])
|
|
.then(res => {
|
|
this.set(res);
|
|
})
|
|
.catch(() => {
|
|
onFail();
|
|
if (this.config.allowFavouritesFromLocalstorage) {
|
|
this.set(newFavourites);
|
|
setFavouriteStorage(newFavourites);
|
|
}
|
|
this.fetchComplete();
|
|
});
|
|
} else {
|
|
this.set(newFavourites);
|
|
setFavouriteStorage(newFavourites);
|
|
}
|
|
}
|
|
|
|
static handlers = {
|
|
SaveFavourite: 'saveFavourite',
|
|
UpdateFavourites: 'updateFavourites',
|
|
DeleteFavourite: 'deleteFavourite',
|
|
FetchFavourites: 'fetchFavourites',
|
|
FetchFavouritesComplete: 'fetchComplete',
|
|
};
|
|
}
|