aboutsummaryrefslogtreecommitdiff
blob: b4ddaa9b02ed6ac57f04346903cdba97f8951a68 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
import React, { useEffect, useRef, useState } from 'react';

import { Group, Trip } from '../../models';

import styles from './Sidebar.module.css';

interface Props {
  trips: Trip[];
  currentTrip: Trip;
  groups: Group[];
  currentGroup: Group | undefined;
  headline?: string;
  asideOpen: boolean;
  handleClose: () => void;
  handleGroupChange: (groupIndex: number, openGallery?: boolean) => void;
  handleTripChange: (tripIndex: number) => void;
}

export default function Sidebar({
  trips,
  currentTrip,
  groups,
  currentGroup,
  asideOpen,
  handleClose,
  handleGroupChange,
  handleTripChange,
}: Props): JSX.Element {
  const [tripListOpen, setTripListOpen] = useState(false);
  const wrapperRef = useRef<null | HTMLElement>(null);

  useEffect(() => {
    function handleClickOutside(e: Event): void {
      if (
        wrapperRef.current !== null &&
        e.target !== null &&
        !wrapperRef.current.contains(e.target as Node)
      ) {
        handleClose();
      }
    }

    document.addEventListener('mousedown', handleClickOutside);
    return () => {
      document.removeEventListener('mousedown', handleClickOutside);
    };
  }, [wrapperRef]);

  function groupChangeHandler(groupIndex: number, openGallery?: boolean): void {
    handleGroupChange(groupIndex, openGallery);
    handleClose();
  }

  function tripChangeHandler(tripIndex: number): void {
    handleTripChange(tripIndex);
    setTripListOpen(false);
  }

  function buildGroupDescription(
    template: string | undefined,
    tokens: { [key: string]: string | number } | undefined,
  ): string {
    if (template === undefined) {
      return '';
    }

    let description = template;

    if (tokens === undefined) {
      return description;
    }

    Object.keys(tokens).forEach((key) => {
      description = description.replaceAll(`{${key}}`, `${tokens[key]}`);
    });

    return description;
  }

  const asideStyle = asideOpen ? `${styles.aside} ${styles.asideOpen}` : styles.aside;

  return (
    <aside ref={wrapperRef} className={asideStyle}>
      {currentTrip.name !== undefined && (
        <div className={styles.headline}>
          <h2>{currentTrip.name}</h2>
          {trips.length > 1 && (
            <button
              type="button"
              title="Show list of trips"
              onClick={() => setTripListOpen(!tripListOpen)}
            >
              <div></div>
            </button>
          )}
          {tripListOpen && (
            <div className={styles.tripList}>
              <ul>
                {trips.map((t, i) => (
                  <li key={i}>
                    <a onClick={() => tripChangeHandler(i)}>{t.name}</a>
                  </li>
                ))}
              </ul>
            </div>
          )}
        </div>
      )}
      <ul className={styles.list}>
        {groups.map((group, index) => {
          const listItemStyle =
            group.id === currentGroup?.id
              ? `${styles.listItem} ${styles.listItemActive}`
              : styles.listItem;

          return (
            <li key={index}>
              <a
                onClick={() => groupChangeHandler(index)}
                onKeyPress={() => groupChangeHandler(index)}
                tabIndex={0}
                role="menuitem"
                className={listItemStyle}
              >
                <div className={styles.listItemContent}>
                  <b>{group.name}</b>
                  <br />
                  <div className={styles.preformatted}>
                    {buildGroupDescription(group.description, group.metadata)}
                  </div>
                </div>
                <button
                  type="button"
                  title="Show gallery"
                  className={styles.listItemButton}
                  onClick={(e) => {
                    e.stopPropagation();
                    groupChangeHandler(index, true);
                  }}
                >
                  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512">
                    <path d="M512 32H160c-35.35 0-64 28.65-64 64v224c0 35.35 28.65 64 64 64H512c35.35 0 64-28.65 64-64V96C576 60.65 547.3 32 512 32zM528 320c0 8.822-7.178 16-16 16h-16l-109.3-160.9C383.7 170.7 378.7 168 373.3 168c-5.352 0-10.35 2.672-13.31 7.125l-62.74 94.11L274.9 238.6C271.9 234.4 267.1 232 262 232c-5.109 0-9.914 2.441-12.93 6.574L176 336H160c-8.822 0-16-7.178-16-16V96c0-8.822 7.178-16 16-16H512c8.822 0 16 7.178 16 16V320zM224 112c-17.67 0-32 14.33-32 32s14.33 32 32 32c17.68 0 32-14.33 32-32S241.7 112 224 112zM456 480H120C53.83 480 0 426.2 0 360v-240C0 106.8 10.75 96 24 96S48 106.8 48 120v240c0 39.7 32.3 72 72 72h336c13.25 0 24 10.75 24 24S469.3 480 456 480z" />
                  </svg>
                </button>
              </a>
            </li>
          );
        })}
      </ul>
    </aside>
  );
}