diff options
-rw-r--r-- | src/App.tsx | 45 | ||||
-rw-r--r-- | src/lib/util.ts | 10 | ||||
-rw-r--r-- | src/models/Group.ts | 4 | ||||
-rw-r--r-- | src/models/Trip.ts | 14 | ||||
-rw-r--r-- | src/models/index.guard.ts | 7 |
5 files changed, 61 insertions, 19 deletions
diff --git a/src/App.tsx b/src/App.tsx index 8dece4e..3f15a7a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,12 +4,13 @@ import PhotoSwipeLightbox from 'photoswipe/lightbox'; import Sidebar from './components/Sidebar/Sidebar';
import Map from './components/Map/Map';
import { createLightbox } from './components/Lightbox/Lightbox';
+import LoadingScreen from './components/LoadingScreen/LoadingScreen';
import { MediaType, Trip } from './models';
import { isTrip } from './models/index.guard';
+import { getObjectProperty } from './lib/util';
import styles from './App.module.css';
import 'photoswipe/style.css';
-import LoadingScreen from './components/LoadingScreen/LoadingScreen';
function App(): JSX.Element {
const [allTrips, setAllTrips] = useState<Trip[]>([]);
@@ -49,39 +50,55 @@ function App(): JSX.Element { }
}
- async function getTrip(url: string): Promise<Trip | undefined> {
+ async function getTrip(trip: Trip): Promise<Trip | undefined> {
try {
- if (url === undefined) {
+ if (trip.url === undefined) {
return;
}
- const res = await fetch(url);
+ const res = await fetch(trip.url);
const data: Trip = await res.json();
if (!isTrip(data)) {
throw new Error('The requested data file has incorrect structure or types.');
}
- const trip = {
+ const fullTrip = {
...data,
- url,
+ ...trip,
downloaded: true,
};
if (data.groups !== undefined) {
-
- trip.groups = [
+ const sortProperty = fullTrip.sortProperty ?? 'name';
+ const sortOrder = fullTrip.sortOrder ?? false;
+
+ data.groups.sort((a, b) => {
+ let aVal = getObjectProperty(a, sortProperty);
+ let bVal = getObjectProperty(b, sortProperty);
+
+ aVal = aVal === undefined ? (typeof bVal === "string" ? "" : 0) : aVal;
+ bVal = bVal === undefined ? (typeof aVal === "string" ? "" : 0) : bVal;
+
+ if (sortOrder) {
+ return aVal > bVal ? -1 : (aVal === bVal ? 0 : 1);
+ }
+
+ return aVal > bVal ? 1 : (aVal === bVal ? 0 : -1);
+ });
+
+ fullTrip.groups = [
{
id: 'all',
name: 'Show all',
media: data.groups?.flatMap((g) => g.media),
- geoData: data.groups?.flatMap((g) => g.geoData !== undefined ? g.geoData : [])
+ geoData: data.groups?.flatMap((g) => (g.geoData !== undefined ? g.geoData : [])),
},
...data.groups,
];
}
- return trip;
+ return fullTrip;
} catch (err) {
setError(`An error occurred while retrieving data: "${err as string}"`);
console.error(err);
@@ -89,7 +106,7 @@ function App(): JSX.Element { }
function updateAllTrips(trips: Trip[], trip: Trip): void {
- const updatedTrips = (trips).map((t) => {
+ const updatedTrips = trips.map((t) => {
if (t.id === trip.id) {
t = trip;
}
@@ -106,7 +123,7 @@ function App(): JSX.Element { }
async function getFirstTrip(trips: Trip[]): Promise<void> {
- const trip = await getTrip(trips[0].url);
+ const trip = await getTrip(trips[0]);
if (trip !== undefined) {
updateAllTrips(trips, trip);
@@ -131,7 +148,7 @@ function App(): JSX.Element { return await getFirstTrip(trips);
}
- const trip = await getTrip(trips[tripIndex].url);
+ const trip = await getTrip(trips[tripIndex]);
if (trip === undefined) {
return await getFirstTrip(trips);
@@ -232,7 +249,7 @@ function App(): JSX.Element { setIsLoading(true);
if (!allTrips[tripIndex].downloaded) {
- void getTrip(allTrips[tripIndex].url).then((trip) => {
+ void getTrip(allTrips[tripIndex]).then((trip) => {
if (trip === undefined) {
return;
}
diff --git a/src/lib/util.ts b/src/lib/util.ts index 1b000c0..ed216e7 100644 --- a/src/lib/util.ts +++ b/src/lib/util.ts @@ -27,4 +27,12 @@ export function distanceBetween(latlng1: number[], latlng2: number[]): number { return R * c;
}
-export default { secondsToTimeString, distanceBetween };
+export function getObjectProperty (object: any, path: string): any {
+ if (object == null) {
+ return object;
+ }
+ const parts = path.split('.');
+ return parts.reduce((object, key) => object?.[key], object);
+};
+
+export default { secondsToTimeString, distanceBetween, getObjectProperty };
diff --git a/src/models/Group.ts b/src/models/Group.ts index 9b3aa6d..c0d281d 100644 --- a/src/models/Group.ts +++ b/src/models/Group.ts @@ -19,7 +19,7 @@ export default interface Group { description?: string;
/**
- * Medias in the group.
+ * Media in the group.
*/
media: MediaItem[];
@@ -32,4 +32,6 @@ export default interface Group { * Metadata that can be displayed in the description.
*/
metadata?: { [key: string]: string | number };
+
+ [key: string]: any;
}
diff --git a/src/models/Trip.ts b/src/models/Trip.ts index 7f92669..46c462d 100644 --- a/src/models/Trip.ts +++ b/src/models/Trip.ts @@ -19,10 +19,22 @@ export default interface Trip { /**
* URL to a JSON file containing data for the trip.
*/
- url: string;
+ url?: string;
/**
* Property indicating if the trip data has been already downloaded.
*/
downloaded: boolean;
+
+ /**
+ * A group property to use while sorting groups.
+ * Nested properties should be delimited with a dot.
+ * Default: name.
+ */
+ sortProperty?: string;
+
+ /**
+ * Sort order. true = descending, false = ascending.
+ */
+ sortOrder?: boolean;
}
diff --git a/src/models/index.guard.ts b/src/models/index.guard.ts index d564ff9..6e9265f 100644 --- a/src/models/index.guard.ts +++ b/src/models/index.guard.ts @@ -47,8 +47,11 @@ export function isTrip(obj: unknown): obj is Trip { typeof typedObj.id === 'string' &&
typeof typedObj.name === 'string' &&
(typeof typedObj.groups === 'undefined' ||
- (Array.isArray(typedObj.groups) && typedObj.groups.every((e: any) => isGroup(e)))
- );
+ (Array.isArray(typedObj.groups) && typedObj.groups.every((e: any) => isGroup(e)))) &&
+ (typeof typedObj.url === 'undefined' || typeof typedObj.url === 'string') &&
+ (typeof typedObj.downloaded === 'undefined' || typeof typedObj.downloaded === 'boolean') &&
+ (typeof typedObj.sortProperty === 'undefined' || typeof typedObj.sortProperty === 'string') &&
+ (typeof typedObj.sortOrder === 'undefined' || typeof typedObj.sortOrder === 'boolean');
if (!isValid) {
throw new Error(`Invalid object: ${JSON.stringify(obj)}`);
|