all repos — caroster @ 2d426f3ead783465e40efb9d91142388b5ec43da

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