all repos — caroster @ 7aaf2e08839a69d11fe38936bef5abaf5789b853

[Octree] Group carpool to your event https://caroster.io

frontend/containers/EventBar/index.tsx (view raw)

  1import {useEffect, useState, useReducer} from 'react';
  2import {useRouter} from 'next/router';
  3import Link from 'next/link';
  4import {makeStyles} from '@material-ui/core/styles';
  5import AppBar from '@material-ui/core/AppBar';
  6import Toolbar from '@material-ui/core/Toolbar';
  7import Typography from '@material-ui/core/Typography';
  8import IconButton from '@material-ui/core/IconButton';
  9import Tooltip from '@material-ui/core/Tooltip';
 10import Avatar from '@material-ui/core/Avatar';
 11import Icon from '@material-ui/core/Icon';
 12import clsx from 'clsx';
 13import {useTranslation} from 'react-i18next';
 14import useAuthStore from '../../stores/useAuthStore';
 15import useEventStore from '../../stores/useEventStore';
 16import useTourStore from '../../stores/useTourStore';
 17import useProfile from '../../hooks/useProfile';
 18import useSettings from '../../hooks/useSettings';
 19import GenericMenu from '../GenericMenu';
 20import EventDetails from '../EventDetails';
 21import useBannerStore from '../../stores/useBannerStore';
 22import Banner from '../../components/Banner';
 23
 24const EventBar = ({event, onAdd, onSave, onShare}) => {
 25  const {t} = useTranslation();
 26  const router = useRouter();
 27  const [detailsOpen, toggleDetails] = useReducer(i => !i, false);
 28  const [anchorEl, setAnchorEl] = useState(null);
 29  const isEditing = useEventStore(s => s.isEditing);
 30  const setIsEditing = useEventStore(s => s.setIsEditing);
 31  const token = useAuthStore(s => s.token);
 32  const {user} = useProfile();
 33  const settings = useSettings();
 34  const setTour = useTourStore(s => s.setTour);
 35  const tourStep = useTourStore(s => s.step);
 36  const bannerOffset = useBannerStore(s => s.offset);
 37  const bannerHeight = useBannerStore(s => s.height);
 38  const classes = useStyles({detailsOpen, bannerOffset, bannerHeight});
 39  const announcement = settings?.announcement || '';
 40  const [lastAnnouncementSeen, setLastAnnouncementSeen] = useState(
 41    typeof localStorage !== 'undefined'
 42      ? localStorage.getItem('lastAnnouncementSeen')
 43      : ''
 44  );
 45  const showAnnouncement =
 46    announcement !== '' && announcement !== lastAnnouncementSeen;
 47
 48  const onBannerClear = () => {
 49    if (typeof announcement != 'undefined') {
 50      localStorage.setItem('lastAnnouncementSeen', String(announcement));
 51    }
 52    setLastAnnouncementSeen(announcement);
 53  };
 54
 55  useEffect(() => {
 56    onTourChange(toggleDetails);
 57  }, [tourStep]);
 58
 59  useEffect(() => {
 60    if (!detailsOpen) setIsEditing(false);
 61  }, [detailsOpen]); // eslint-disable-line react-hooks/exhaustive-deps
 62
 63  const signUp = () =>
 64    router.push({
 65      pathname: '/auth/register',
 66      state: {event: event?.id},
 67    });
 68  const signIn = () => router.push('/auth/login');
 69  const goToDashboard = () => router.push('/dashboard');
 70  const goProfile = () => router.push('/profile');
 71
 72  const onTourRestart = () => setTour({showWelcome: true});
 73
 74  const noUserMenuActions = [
 75    {
 76      label: t('event.actions.add_to_my_events'),
 77      onClick: () => {
 78        onAdd(true);
 79      },
 80      id: 'AddToMyEventsTab',
 81    },
 82    {divider: true},
 83    {
 84      label: t('menu.login'),
 85      onClick: signIn,
 86      id: 'SignInTab',
 87    },
 88    {
 89      label: t('menu.register'),
 90      onClick: signUp,
 91      id: 'SignUpTab',
 92    },
 93    {divider: true},
 94    {
 95      label: t('menu.tour'),
 96      onClick: () => {
 97        setAnchorEl(null);
 98        onTourRestart();
 99      },
100      id: 'TourTab',
101    },
102  ];
103
104  const loggedMenuActions = [
105    {
106      label: t('menu.dashboard'),
107      onClick: goToDashboard,
108      id: 'GoToDashboardTab',
109    },
110    {
111      label: t('menu.profile'),
112      onClick: goProfile,
113      id: 'ProfileTab',
114    },
115    {divider: true},
116    {
117      label: t('menu.tour'),
118      onClick: () => {
119        setAnchorEl(null);
120        onTourRestart();
121      },
122      id: 'TourTab',
123    },
124  ];
125
126  const menuActions = token ? loggedMenuActions : noUserMenuActions;
127  const userInfos = user
128    ? [{label: user.username, id: 'Email'}, {divider: true}]
129    : [];
130
131  const appLink = user ? '/dashboard' : settings?.['about_link'] || '';
132
133  const UserIcon = user ? (
134    <Avatar className={classes.avatar}>
135      {`${user.username[0]}`.toUpperCase()}
136    </Avatar>
137  ) : (
138    <Icon>more_vert</Icon>
139  );
140
141  return (
142    <AppBar
143      className={classes.appbar}
144      position="fixed"
145      color="primary"
146      id={(isEditing && 'EditEvent') || (detailsOpen && 'Details') || 'Menu'}
147    >
148      <Banner
149        message={announcement}
150        open={showAnnouncement}
151        onClear={onBannerClear}
152      />
153      <Toolbar>
154        <div className={classes.name}>
155          <Link href={appLink}>
156            <img
157              className={classes.logo}
158              src="/assets/Logo_in_beta.svg"
159              alt="Logo"
160            />
161          </Link>
162          <Tooltip title={event.name}>
163            <Typography
164              variant="h6"
165              noWrap
166              id="MenuHeaderTitle"
167              className={classes.title}
168            >
169              {event.name}
170            </Typography>
171          </Tooltip>
172
173          {detailsOpen && (
174            <IconButton
175              className="tour_event_edit"
176              color="inherit"
177              edge="end"
178              id="HeaderAction"
179              onClick={isEditing ? onSave : () => setIsEditing(true)}
180            >
181              <Icon>{isEditing ? 'done' : 'edit'}</Icon>
182            </IconButton>
183          )}
184        </div>
185        {detailsOpen ? (
186          <IconButton
187            color="inherit"
188            edge="end"
189            id="CloseDetailsBtn"
190            onClick={() => {
191              setIsEditing(false);
192              toggleDetails();
193            }}
194          >
195            <Icon>close</Icon>
196          </IconButton>
197        ) : (
198          <>
199            <IconButton
200              className={classes.shareIcon}
201              color="inherit"
202              edge="end"
203              id="ShareBtn"
204              onClick={toggleDetails}
205            >
206              <Icon>share</Icon>
207            </IconButton>
208            <IconButton
209              className={clsx(classes.iconButtons, 'tour_event_infos')}
210              color="inherit"
211              edge="end"
212              id="ShareBtn"
213              onClick={toggleDetails}
214            >
215              <Icon>information_outline</Icon>
216            </IconButton>
217            <IconButton
218              color="inherit"
219              edge="end"
220              id="MenuMoreInfo"
221              onClick={e => setAnchorEl(e.currentTarget)}
222            >
223              {UserIcon}
224            </IconButton>
225          </>
226        )}
227        {!detailsOpen && (
228          <GenericMenu
229            anchorEl={anchorEl}
230            setAnchorEl={setAnchorEl}
231            actions={[
232              ...userInfos,
233              ...[
234                {
235                  label: detailsOpen
236                    ? t('event.actions.hide_details')
237                    : t('event.actions.show_details'),
238                  onClick: e => {
239                    setAnchorEl(null);
240                    toggleDetails();
241                  },
242                  id: 'DetailsTab',
243                },
244              ],
245              ...menuActions,
246            ]}
247          />
248        )}
249      </Toolbar>
250      {detailsOpen && (
251        <EventDetails toggleDetails={toggleDetails} onShare={onShare} />
252      )}
253    </AppBar>
254  );
255};
256
257const onTourChange = (toggleDetails: Function) => {
258  const {prev, step, isCreator} = useTourStore.getState();
259  const fromTo = (step1: number, step2: number) =>
260    prev === step1 && step === step2;
261
262  if (isCreator) {
263    if (fromTo(3, 2) || fromTo(2, 3) || fromTo(4, 5)) toggleDetails();
264  } else if (fromTo(2, 3) || fromTo(3, 2) || fromTo(3, 4)) toggleDetails();
265};
266
267const useStyles = makeStyles(theme => ({
268  appbar: ({detailsOpen, bannerOffset, bannerHeight}) => ({
269    overflow: 'hidden',
270    minHeight: detailsOpen ? '100vh' : theme.mixins.toolbar.minHeight,
271    overflowY: detailsOpen ? 'scroll' : 'hidden',
272    transition: 'height 0.3s ease',
273    marginTop: bannerOffset - bannerHeight,
274  }),
275  logo: {
276    marginRight: theme.spacing(2),
277    width: 64,
278    height: 32,
279    cursor: 'pointer',
280  },
281  name: {
282    flexGrow: 1,
283    display: 'flex',
284    alignItems: 'center',
285  },
286  title: {
287    maxWidth: `calc(100vw - ${theme.spacing(30)}px)`,
288  },
289  iconButtons: {
290    margin: theme.spacing(0),
291  },
292  avatar: {
293    width: theme.spacing(3),
294    height: theme.spacing(3),
295    fontSize: 16,
296  },
297  shareIcon: {
298    marginRight: 0,
299  },
300}));
301
302export default EventBar;