VandyHacks/vaken

View on GitHub
src/client/routes/events/CheckInEvents.tsx

Summary

Maintainability
A
2 hrs
Test Coverage
F
55%
import React, { FC, useMemo } from 'react';
import styled from 'styled-components';
import { toast } from 'react-toastify';
import { Button } from '../../components/Buttons/Button';
import FloatingPopup from '../../components/Containers/FloatingPopup';
import { FlexColumn, FlexStartColumn } from '../../components/Containers/FlexContainers';
import { Title } from '../../components/Text/Title';
import STRINGS from '../../assets/strings.json';
import { SmallCenteredText } from '../../components/Text/SmallCenteredText';
import { GraphQLErrorMessage } from '../../components/Text/ErrorMessage';
import {
    useCheckInUserToEventAndUpdateEventScoreMutation,
    CheckInUserToEventAndUpdateEventScoreMutationHookResult,
    useEventsForHackersQuery,
    useMyEventStatusQuery,
} from '../../generated/graphql';
import { Spinner } from '../../components/Loading/Spinner';

const HackerDashBG = styled(FloatingPopup)`
    border-radius: 8px;
    height: min-content;
    width: 36rem;
    background: ${STRINGS.BACKGROUND_DARK_SECONDARY};
    padding: 1.5rem;

    @media screen and (max-width: 456px) {
        width: 100%;
    }

    @media screen and (max-width: 400px) {
        a {
            width: 100%;
        }
    }
`;

function getOnCheckIn(
    checkIn: CheckInUserToEventAndUpdateEventScoreMutationHookResult[0]
): (eventId: string, userId: string) => Promise<void> {
    return async function onCheckIn(eventId: string, userId: string) {
        try {
            await checkIn({
                variables: {
                    input: {
                        event: eventId,
                        user: userId,
                    },
                },
            });
            toast.dismiss();
            return void toast.success('You have been checked in successfully!');
        } catch (e) {
            toast.dismiss();
            if (e.message.includes('is already checked into event')) {
                return void toast.error('You are already checked in!');
            }
            return void toast.error('Check-in failed!');
        }
    };
}

export const CheckInEvent: FC = () => {
    const events = useEventsForHackersQuery();
    const hacker = useMyEventStatusQuery();
    const [checkIn] = useCheckInUserToEventAndUpdateEventScoreMutation();
    const onCheckIn = useMemo(() => getOnCheckIn(checkIn), [checkIn]);

    if (events.loading || hacker.loading) {
        return <Spinner />;
    }

    if (events.error || hacker.error || !events.data || !hacker.data || !hacker.data.me) {
        return <GraphQLErrorMessage text={STRINGS.GRAPHQL_ORGANIZER_ERROR_MESSAGE} />;
    }

    // Satisfy type system that reference is still defined in closures below.
    const { me } = hacker.data;

    const currentEvents = events.data.events.filter(({ startTimestamp, duration }) => {
        const TIME_BUFFER = 5; // 5 minutes
        const delta = (Date.now() - startTimestamp) / (1000 * 60); // Time diff in minutes
        return delta >= -1 * TIME_BUFFER && delta <= duration + TIME_BUFFER;
    });

    return (
        <FlexStartColumn>
            <HackerDashBG>
                <FlexColumn>
                    <Title fontSize="1.75rem">Your Score:</Title>
                    <SmallCenteredText color={`${STRINGS.DARK_TEXT_COLOR}`} fontSize="1.3rem" margin="1rem">
                        <span style={{ fontWeight: 'bold' }}>{me.eventScore ?? '0'}</span>
                    </SmallCenteredText>
                    <Title fontSize="1.75rem">Ongoing Events:</Title>
                    {currentEvents.map(row => (
                        <FlexColumn key={row.id}>
                            <SmallCenteredText
                                color={`${STRINGS.DARK_TEXT_COLOR}`}
                                fontSize="1.3rem"
                                margin="1.4rem">
                                <span style={{ fontWeight: 'bold' }}>{row.name}</span>
                            </SmallCenteredText>
                            <Button
                                key={row.id}
                                large
                                async
                                disabled={me.eventsAttended.includes(row.id)}
                                onClick={() => onCheckIn(row.id, me.id)}>
                                {me.eventsAttended.includes(row.id) ? 'Checked In!' : 'Check In'}
                            </Button>
                        </FlexColumn>
                    ))}
                </FlexColumn>
            </HackerDashBG>
        </FlexStartColumn>
    );
};

export default CheckInEvent;