Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added the page_views and events #20

Open
wants to merge 25 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f78d6f6
Landing Page! (#11)
abhinavpappu Nov 5, 2020
2de69d0
added most of api.js types
SarthakKamboj Nov 5, 2020
5234f75
Merge branch 'dev' of https://github.com/SarthakKamboj/site into dev
SarthakKamboj Nov 5, 2020
444ecc4
removed types.ts
SarthakKamboj Nov 5, 2020
c7aba4e
Merge pull request #12 from HackIllinois/dev
abhinavpappu Nov 7, 2020
f3365b8
updated types.ts
SarthakKamboj Nov 9, 2020
4141e54
Merge branch 'master' of https://github.com/HackIllinois/site into dev
SarthakKamboj Nov 9, 2020
46279a3
added files from hack-this repo
SarthakKamboj Nov 9, 2020
b38f582
commented google analytics part
SarthakKamboj Nov 10, 2020
4605304
Merge branch 'dev' of https://github.com/HackIllinois/site
SarthakKamboj Nov 10, 2020
bcfc979
removed site folder
SarthakKamboj Nov 10, 2020
6eb4e74
merged w/ master
SarthakKamboj Nov 10, 2020
0ceaab9
updated
SarthakKamboj Nov 10, 2020
367ea08
updated types for AuthenticatedRoute
SarthakKamboj Nov 10, 2020
bd89cf9
temporary changed loading comp. to div with loading text
SarthakKamboj Nov 10, 2020
700c45e
added types to StaticFileRedirect
SarthakKamboj Nov 10, 2020
5709baa
added types for events.ts
SarthakKamboj Nov 10, 2020
ce87579
added types to api.ts
SarthakKamboj Nov 12, 2020
6014ec6
Add sponsorship doc (with analytics) (#15)
abhinavpappu Nov 23, 2020
294c819
fixed some eslint errors
SarthakKamboj Nov 26, 2020
9a72586
pulled changes from hackillinois dev repo
SarthakKamboj Nov 26, 2020
f93c68d
added ga events and pageviews
SarthakKamboj Dec 30, 2020
1e07be0
fixed conflicts
SarthakKamboj Dec 30, 2020
be66eef
pulled and made a few changes in Auth
SarthakKamboj Dec 30, 2020
22f7509
added events for mobile
SarthakKamboj Dec 30, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"react/require-default-props": "off",
"linebreak-style": "off",
"no-param-reassign": "off",
"react/prop-types": "off",
"max-len": "off"
}
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@typescript-eslint/parser": "^4.6.0",
"eslint-config-airbnb-typescript": "^12.0.0",
"node-sass": "^4.14.1",
"prop-types": "^15.7.2",
"query-string": "^6.13.6",
"react": "^17.0.1",
"react-dom": "^17.0.1",
Expand Down
10 changes: 9 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';

// import ReactGa from 'react-ga';
import Home from 'pages/Home';
import Auth from 'pages/Auth';
import StaticFileRedirect from 'components/StaticFileRedirect';

function App(): JSX.Element {
// const notifyGA = (path: string) => {
// switch (path) {
// case "/":
// ReactGa.pageview()
// break;
// };
// };

return (
<Router>
<Switch>
Expand Down
8 changes: 8 additions & 0 deletions src/GARouteUpdater.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from 'react';

const GARouteUpdater: React.FC = () => (
<>
</>
);

export default GARouteUpdater;
158 changes: 158 additions & 0 deletions src/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import { MethodType, FileType, RegistrationType, EventResType } from './types';

const API = 'https://api.hackillinois.org';
export const isAuthenticated = () => sessionStorage.getItem('token');

function request(method: MethodType, endpoint: string, body?: any) {
const getSessionToken = (): string => {
const token = isAuthenticated();
if (token === null) {
throw new Error('token is null');
}
return token;
};
return fetch(API + endpoint, {
method,
headers: {
Authorization: getSessionToken(),
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
})
.then((res: Response) => {
if (res.status === 200) {
return res.json();
}
throw new Error('response status code not 200');
})
.catch((err: Error) => {
console.error(err.message);
});
}

export function authenticate(to: string) {
if (process.env.REACT_APP_TOKEN) {
sessionStorage.setItem('token', process.env.REACT_APP_TOKEN);
} else {
to = `${API}/auth/github/?redirect_uri=${to}`;
}
window.location.replace(to);
}

export function getToken(code: string | string[] | null) {
return request('POST', '/auth/code/github/', { code }).then((res) => res.token);
}

type GetRolesResType = {
id: string;
roles: string[];
};

export function getRoles() {
return request('GET', '/auth/roles/').then(
(res) => (res as GetRolesResType).roles,
);
}

export function getRolesSync(): string[] {
const token = sessionStorage.getItem('token');
if (token) {
try {
const tokenData = JSON.parse(atob(token.split('.')[1]));
return tokenData.roles;
} catch (e) {
// if the token is incorrectly formatted, we just ignore it and return the default []
}
}
return [];
}

export function getRegistration(role: string): Promise<EventResType> {
return request('GET', `/registration/${role}/`);
}

// this function does not have a return type because different roles have different response types
export function register(
isEditing: boolean,
role: string,
registration: RegistrationType,
) {
const method = isEditing ? 'PUT' : 'POST';
return request(method, `/registration/${role}/`, registration);
}

type GetRsvpResType = {
id: string;
isAttending: boolean,
};

export function getRSVP(): Promise<GetRsvpResType> {
return request('GET', '/rsvp/');
}

export function rsvp(isEditing: boolean, registration: RegistrationType): Promise<GetRsvpResType> {
const method = isEditing ? 'PUT' : 'POST';
return request(method, '/rsvp/', registration);
}

export function uploadFile(file: File, type: FileType) {
return request('GET', `/upload/${type}/upload/`)
.then((res) => fetch(res[type], {
method: 'PUT',
headers: { 'Content-Type': file.type },
body: file,
}))
.then((res) => {
if (res.ok) {
return res;
}
throw new Error('response did not have status 200');
})
.catch((err: Error) => {
console.error(err);
});
}

type GetQrResType = {
id: string;
qrInfo:string;
};

export function getQR():Promise<GetQrResType> {
return request('GET', '/user/qr/');
}

export function getPrizes() {
return request('GET', '/upload/blobstore/prizes/').then((res) => res.data);
}

type RefreshTokenResType = {
token: string;
};
export function refreshToken(): Promise<void> {
return request('GET', '/auth/token/refresh/').then((res:RefreshTokenResType) => sessionStorage.setItem('token', res.token));
}

export function getMentorTimeslots() {
return request('GET', '/upload/blobstore/mentor-timeslots/').then(
(res) => res.data,
);
}

export function setMentorTimeslots(data: Record<string, string>) {
return request('PUT', '/upload/blobstore/', {
id: 'mentor-timeslots',
data,
})
.then((res: Response) => res.json())
.then((res: any) => res.data)
.catch((err: Error) => console.log(err));
}

type GetEventsResType = {
events: EventResType[]
};

export function getEvents() {
return request('GET', '/event/').then((res: GetEventsResType) => res.events);
}
106 changes: 106 additions & 0 deletions src/events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/* Example return object:
[
{
date: Date(),
dayOfWeek: "Friday",
month: "February",
dayOfMonth: 28,
events: [ ... ] // all the event objects occuring on this day
},
...
]
*/

import { DayType, EventType, WeekType } from './types';

export const sortEventsIntoDays = (events: EventType[]) => {
// separate events by day into a map like so {"2/28/2019": [], "3/1/2019": [], ...}
const eventsByDay: Map<string, EventType[]> = new Map();
events.forEach((event) => {
const dateString = new Date(event.startTime * 1000).toLocaleDateString(
'en-US',
);
const eventsOnDay = eventsByDay.get(dateString);
if (eventsOnDay) {
eventsOnDay.push(event);
} else {
eventsByDay.set(dateString, [event]);
}
});

// convert the map into an array of day objects
const days: DayType[] = [];

Array.from(eventsByDay.entries()).forEach(([dateString, eventsPerDay]) => {
const date = new Date(dateString);
days.push({
date,
dayOfWeek: date.toLocaleDateString('en-US', { weekday: 'long' }),
month: date.toLocaleString('en-US', { month: 'long' }),
dayOfMonth: date.getDate(),
events: eventsPerDay.sort((a: EventType, b: EventType) => {
if (a.startTime === b.startTime) {
return a.endTime - b.endTime;
}
return a.startTime - b.startTime;
}),
});
});

// sort the days in order (just using the startTime of the first event
// on that day to prevent additional calculations)
days.sort((a, b) => a.events[0].startTime - b.events[0].startTime);

return days;
};

const addDays = (date: Date, days: number): Date => {
const newDate = new Date(date);
newDate.setDate(date.getDate() + days);
return newDate;
};

// Returns a 2d array in following format
// [[{ date: Date, index?: Number }, ...], ...]
// if index is specified, then that date was part of the dates provided as a parameter

export const getSurroundingWeeks = (startDate: Date, numDays: number) => {
if (startDate && numDays >= 1) {
const weeks: [WeekType[]] = [[]];
let currentWeek = weeks[0];

// Add all the days preceding startDate in the week of startDate
for (let i = -startDate.getDay(); i < 0; i += 1) {
// -startDate.getDay() effectively gets the offset to the sunday before startDate
currentWeek.push({
date: addDays(startDate, i),
});
}

// Add all the days that were specified in the parameters
for (let i = 0; i < numDays; i += 1) {
if (currentWeek.length >= 7) {
// when we get to the end of this week, add another week
currentWeek = [];
weeks.push(currentWeek);
}

currentWeek.push({
date: addDays(startDate, i),
index: i, // note that these dates get indices
});
}

// Add remaining days in the week of the last date
const endDate = currentWeek[currentWeek.length - 1].date;
for (let i = 1; i < 7 - endDate.getDay(); i += 1) {
currentWeek.push({
date: addDays(endDate, i),
});
}

return weeks;
}

return [];
};
2 changes: 1 addition & 1 deletion src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import App from './App';
import reportWebVitals from './reportWebVitals';

ReactGA.initialize('G-2D2S4GLZPR', {
testMode: process.env.NODE_ENV !== 'production',
// testMode: process.env.NODE_ENV !== 'production',
});

ReactDOM.render(
Expand Down
49 changes: 28 additions & 21 deletions src/pages/Auth/index.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,47 @@
import React from 'react';
import React, { useEffect } from 'react';
import queryString from 'query-string';
import { useLocation } from 'react-router-dom';

import ReactGa from 'react-ga';
import { getToken } from 'util/api';
// import Loading from 'components/Loading';

function mobileRedirect(os: 'android' | 'ios', code: string) {
ReactGa.event({
category: 'mobile',
action: os,
});
const to = `hackillinois://org.hackillinois.${os}/auth?code=${code}`;
window.location.replace(to);
}

type QueryTypes = {
code?: string;
isAndroid?: string;
isiOS?: string;
to?: string;
};

const Auth: React.FC = () => {
const location = useLocation();

type QueryTypes = {
code?: string;
isAndroid?: string;
isiOS?: string;
to?: string;
};
const { code, isAndroid, isiOS, to }: QueryTypes = queryString.parse(location.search);
useEffect(() => {
ReactGa.pageview('/auth');
const { code, isAndroid, isiOS, to }: QueryTypes = queryString.parse(location.search);

if (code) {
if (isAndroid || isiOS) {
const os = isAndroid ? 'android' : 'ios';
mobileRedirect(os, code);
if (code) {
if (isAndroid || isiOS) {
const os = isAndroid ? 'android' : 'ios';
mobileRedirect(os, code);
} else {
getToken(code).then((token) => {
sessionStorage.setItem('token', token);
window.location.replace(to as string);
});
}
} else {
getToken(code).then((token) => {
sessionStorage.setItem('token', token);
window.location.replace(to as string);
});
window.location.replace('/');
}
} else {
window.location.replace('/');
}

}, []);
return <div>Loading...</div>; // <Loading />;
};

Expand Down
Loading