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)}`);
 |