Browser.tsx 4.78 KB
Newer Older
1
2
3
4
import React, {
  FunctionComponent,
  useCallback,
  useRef,
5
6
  useEffect,
  Fragment
7
8
} from 'react';
import { withRouter, RouteComponentProps } from 'react-router-dom';
9
import { connect } from 'react-redux';
10
import { replace, Replace } from 'connected-react-router';
11

12
13
14
15
16
import BrowserBar from './browser-bar/BrowserBar';
import BrowserImage from './browser-image/BrowserImage';
import BrowserNavBar from './browser-nav/BrowserNavBar';
import TrackPanel from './track-panel/TrackPanel';
import Drawer from './drawer/Drawer';
17

Andrey Azov's avatar
Andrey Azov committed
18
import { RootState } from 'src/store';
19
20
21
22
23
24
import {
  BrowserOpenState,
  BrowserNavStates,
  ChrLocation
} from './browserState';
import {
25
  changeBrowserLocation,
26
  fetchExampleObjectsData,
27
  fetchObjectData,
28
29
  toggleDrawer,
  updateChrLocation,
30
  updateBrowserNavStates
31
} from './browserActions';
32
33
34
import {
  getBrowserOpenState,
  getDrawerOpened,
35
  getBrowserNavOpened,
36
  getChrLocation,
Dan Sheppard's avatar
Dan Sheppard committed
37
  getGenomeSelectorActive,
38
  getBrowserActivated,
39
  getExampleObjects
40
} from './browserSelectors';
41

42
import styles from './Browser.scss';
43

44
import 'static/browser/browser.js';
45
import { getChrLocationFromStr, getChrLocationStr } from './browserHelper';
46
47

type StateProps = {
48
  browserActivated: boolean;
49
  browserNavOpened: boolean;
50
  browserOpenState: BrowserOpenState;
51
  chrLocation: ChrLocation;
52
  drawerOpened: boolean;
53
  exampleObjects: {};
54
  genomeSelectorActive: boolean;
55
56
57
};

type DispatchProps = {
58
59
60
61
  changeBrowserLocation: (
    chrLocation: ChrLocation,
    browserEl: HTMLDivElement
  ) => void;
62
  fetchExampleObjectsData: () => void;
63
  fetchObjectData: (stableId: string) => void;
64
  replace: Replace;
65
  toggleDrawer: (drawerOpened: boolean) => void;
66
67
  updateBrowserNavStates: (browserNavStates: BrowserNavStates) => void;
  updateChrLocation: (chrLocation: ChrLocation) => void;
68
  replace: (path: string) => void;
69
};
70

71
72
type OwnProps = {};

73
type MatchParams = {
74
  location: string;
75
  stableId: string;
76
77
78
79
80
81
82
  species: string;
};

type BrowserProps = RouteComponentProps<MatchParams> &
  StateProps &
  DispatchProps &
  OwnProps;
83

84
85
86
export const Browser: FunctionComponent<BrowserProps> = (
  props: BrowserProps
) => {
87
88
  const browserRef: React.RefObject<HTMLDivElement> = useRef(null);

89
  const dispatchBrowserLocation = (chrLocation: ChrLocation) => {
90
    if (browserRef.current) {
91
      props.changeBrowserLocation(chrLocation, browserRef.current);
92
93
94
    }
  };

95
  useEffect(() => {
96
    const { stableId } = props.match.params;
97
    const location = props.location.search;
98
    const chrLocation = getChrLocationFromStr(location);
99

100
    dispatchBrowserLocation(chrLocation);
101

102
103
    props.fetchObjectData(stableId);
  }, [props.match.params.stableId]);
104

Dan Sheppard's avatar
Dan Sheppard committed
105
  useEffect(() => {
106
107
108
109
    const [, chrStart, chrEnd] = props.chrLocation;

    if (props.browserActivated && chrStart > 0 && chrEnd > 0) {
      dispatchBrowserLocation(props.chrLocation);
Dan Sheppard's avatar
Dan Sheppard committed
110
    }
111
  }, [props.browserActivated]);
Dan Sheppard's avatar
Dan Sheppard committed
112

113
  useEffect(() => {
114
    const { params } = props.match;
115
    const newChrLocationStr = getChrLocationStr(props.chrLocation);
116
117
118
    const newUrl = `/app/browser/${params.species}/${
      params.stableId
    }?region=${newChrLocationStr}`;
119

120
    props.replace(newUrl);
121
  }, [props.chrLocation, props.location.search]);
122

123
  const closeTrack = useCallback(() => {
124
    if (props.drawerOpened === false) {
125
126
127
      return;
    }

128
    props.toggleDrawer(false);
129
  }, [props.drawerOpened]);
130

131
132
  return (
    <section className={styles.browser}>
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
      <Fragment>
        <BrowserBar dispatchBrowserLocation={dispatchBrowserLocation} />
        {props.genomeSelectorActive ? (
          <div className={styles.browserOverlay} />
        ) : null}
        <div className={styles.browserInnerWrapper}>
          <div
            className={`${styles.browserImageWrapper} ${
              styles[props.browserOpenState]
            }`}
            onClick={closeTrack}
          >
            {props.browserNavOpened && !props.drawerOpened ? (
              <BrowserNavBar browserRef={browserRef} />
            ) : null}
            <BrowserImage browserRef={browserRef} />
149
          </div>
150
151
152
153
          <TrackPanel browserRef={browserRef} />
          {props.drawerOpened && <Drawer />}
        </div>
      </Fragment>
154
155
156
    </section>
  );
};
157

158
const mapStateToProps = (state: RootState): StateProps => ({
159
  browserActivated: getBrowserActivated(state),
160
161
  browserNavOpened: getBrowserNavOpened(state),
  browserOpenState: getBrowserOpenState(state),
162
  chrLocation: getChrLocation(state),
163
  drawerOpened: getDrawerOpened(state),
164
  exampleObjects: getExampleObjects(state),
165
  genomeSelectorActive: getGenomeSelectorActive(state)
166
167
});

168
const mapDispatchToProps: DispatchProps = {
169
  changeBrowserLocation,
170
  fetchExampleObjectsData,
171
  fetchObjectData,
172
  replace,
173
174
  toggleDrawer,
  updateBrowserNavStates,
175
176
  updateChrLocation,
  replace
177
178
};

179
180
181
182
183
184
export default withRouter(
  connect(
    mapStateToProps,
    mapDispatchToProps
  )(Browser)
);