From e5ea961330107be48b4646193afbe1e40d64d53d Mon Sep 17 00:00:00 2001 From: Andrew Li Date: Thu, 14 Nov 2019 23:25:46 -0600 Subject: [PATCH 1/3] Add configurable wednesday schedule type for non-wednesdays --- packages/app/__tests__/schedule/query-test.ts | 4 ++++ packages/app/__tests__/store/async-test.ts | 1 + packages/app/ios/Podfile.lock | 8 ++++---- .../WHS.xcodeproj/xcshareddata/xcschemes/WHS.xcscheme | 8 ++------ .../xcshareddata/WorkspaceSettings.xcsettings | 7 ++++++- packages/app/src/actions/async.ts | 3 ++- packages/app/src/components/schedule/ScheduleCard.tsx | 4 ++-- packages/app/src/constants/fetch.ts | 2 +- packages/app/src/constants/store.ts | 1 + packages/app/src/types/store.ts | 2 ++ packages/app/src/utils/process-info.ts | 7 ++++--- packages/app/src/utils/query-schedule.ts | 2 +- packages/app/src/utils/store.ts | 6 ++++++ packages/app/src/utils/utils.ts | 10 +++++++++- 14 files changed, 45 insertions(+), 20 deletions(-) diff --git a/packages/app/__tests__/schedule/query-test.ts b/packages/app/__tests__/schedule/query-test.ts index 069dc5a..12e4b8a 100644 --- a/packages/app/__tests__/schedule/query-test.ts +++ b/packages/app/__tests__/schedule/query-test.ts @@ -321,6 +321,7 @@ describe('schedule querying', () => { noSchool: [new Date(2019, 11, 23), new Date(2019, 11, 24)], earlyDismissal: [new Date(2019, 8, 4), new Date(2019, 10, 11)], lateStart: [new Date(2019, 8, 25), new Date(2019, 10, 1)], + wednesday: [new Date(2019, 10, 15)], semesterOneStart: new Date(2019, 7, 14), semesterOneEnd: new Date(2019, 11, 22), semesterTwoStart: new Date(2020, 0, 5), @@ -393,6 +394,9 @@ describe('schedule querying', () => { it('returns WEDNESDAY for wednesdays', () => { const schedule = getSchedule(new Date(2019, 8, 18)); expect(schedule).toBe(SCHEDULES.WEDNESDAY); + + const setWednesday = getSchedule(new Date(2019, 10, 15)); + expect(setWednesday).toBe(SCHEDULES.WEDNESDAY); }); it('returns REGULAR schedule otherwise', () => { diff --git a/packages/app/__tests__/store/async-test.ts b/packages/app/__tests__/store/async-test.ts index 9ab919e..afe6a2b 100644 --- a/packages/app/__tests__/store/async-test.ts +++ b/packages/app/__tests__/store/async-test.ts @@ -121,6 +121,7 @@ describe('async actions', () => { noSchool: [], earlyDismissal: [], lateStart: [], + wednesday: [], semesterOneStart: null, semesterOneEnd: new Date(datesArray[1].date), semesterTwoStart: null, diff --git a/packages/app/ios/Podfile.lock b/packages/app/ios/Podfile.lock index 560b71d..f2f1b38 100644 --- a/packages/app/ios/Podfile.lock +++ b/packages/app/ios/Podfile.lock @@ -22,7 +22,7 @@ PODS: - DoubleConversion - glog - glog (0.3.5) - - JWT (3.0.0-beta.11): + - JWT (3.0.0-beta.12): - Base64 (~> 1.1.2) - React (0.60.4): - React-Core (= 0.60.4) @@ -154,7 +154,7 @@ DEPENDENCIES: - yoga (from `../node_modules/react-native/ReactCommon/yoga`) SPEC REPOS: - https://github.com/cocoapods/specs.git: + trunk: - Base64 - boost-for-react-native - JWT @@ -238,7 +238,7 @@ SPEC CHECKSUMS: DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2 Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51 glog: 1f3da668190260b06b429bb211bfbee5cd790c28 - JWT: 05028b9624591bba9681bb57df2c5f95fa258bad + JWT: 9b5c05abbcc1a0e69c3c91e1655b3387fc7e581d React: ff7ee2ae5ee1c1d9ae2183b4111045b25294bb01 React-ART: 87b6e9d975551e6177c660dd212529f73ed03681 React-Core: 8e0ea421cae5609d2562850f98421b15030476fa @@ -272,4 +272,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: e6847c2c400140e9f10a719f1e854aeb193e1495 -COCOAPODS: 1.7.5 +COCOAPODS: 1.8.4 diff --git a/packages/app/ios/WHS.xcodeproj/xcshareddata/xcschemes/WHS.xcscheme b/packages/app/ios/WHS.xcodeproj/xcshareddata/xcschemes/WHS.xcscheme index 0223b76..4a863f9 100644 --- a/packages/app/ios/WHS.xcodeproj/xcshareddata/xcschemes/WHS.xcscheme +++ b/packages/app/ios/WHS.xcodeproj/xcshareddata/xcschemes/WHS.xcscheme @@ -69,8 +69,6 @@ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> - - - - + + - - - + + BuildSystemType + Original + PreviewsEnabled + + diff --git a/packages/app/src/actions/async.ts b/packages/app/src/actions/async.ts index 6a84363..140d3e1 100755 --- a/packages/app/src/actions/async.ts +++ b/packages/app/src/actions/async.ts @@ -105,7 +105,7 @@ export function fetchDates(year?: number) { } const [ - assembly, noSchool, earlyDismissal, lateStart, + assembly, noSchool, earlyDismissal, lateStart, wednesday, ] = await Promise.all(DATE_TYPES.map(async (type) => { const dates = await getDates(type, year!); return dates.map((dateObj) => { @@ -131,6 +131,7 @@ export function fetchDates(year?: number) { noSchool, earlyDismissal, lateStart, + wednesday, semesterOneStart, semesterOneEnd, semesterTwoStart, diff --git a/packages/app/src/components/schedule/ScheduleCard.tsx b/packages/app/src/components/schedule/ScheduleCard.tsx index 1f70825..2087716 100644 --- a/packages/app/src/components/schedule/ScheduleCard.tsx +++ b/packages/app/src/components/schedule/ScheduleCard.tsx @@ -118,8 +118,8 @@ const makeCardDayScheduleSelector = () => createSelector( const isFinals = scheduleType === 'FINALS'; const revisedUserDaySchedule = injectAssemblyOrFinalsIfNeeded(schedule, scheduleType, day); - const userDaySchedule = revisedUserDaySchedule - .filter((scheduleItem) => (scheduleItem as ClassItem).title !== 'No Homeroom'); + // Remove homeroom/no homeroom item on wednesday schedules + const userDaySchedule = revisedUserDaySchedule.slice(scheduleType === 'WEDNESDAY' ? 1 : 0); const cardDaySchedule = daySchedule.map(([start, end, modNumber]) => { const startTime = formatTime(start); diff --git a/packages/app/src/constants/fetch.ts b/packages/app/src/constants/fetch.ts index 3d4e3e3..29fcb19 100755 --- a/packages/app/src/constants/fetch.ts +++ b/packages/app/src/constants/fetch.ts @@ -29,7 +29,7 @@ export const SERVER_URL = process.env.NODE_ENV === 'development' export const DATES_URL = `${SERVER_URL}/api/${API_VERSION}/dates`; export const FETCH_TIMEOUT = 5000; -export const DATE_TYPES: DateListType[] = ['assembly', 'no-school', 'early-dismissal', 'late-start']; +export const DATE_TYPES: DateListType[] = ['assembly', 'no-school', 'early-dismissal', 'late-start', 'wednesday']; export const SETTING_TYPES: YearSettingType[] = [ 'semester-one-start', 'semester-one-end', 'semester-two-start', 'semester-two-end', ]; diff --git a/packages/app/src/constants/store.ts b/packages/app/src/constants/store.ts index 5bef0a0..89b7aaf 100755 --- a/packages/app/src/constants/store.ts +++ b/packages/app/src/constants/store.ts @@ -27,6 +27,7 @@ export const initialDatesState: DatesState = { noSchool: [], earlyDismissal: [], lateStart: [], + wednesday: [], semesterOneStart: null, semesterOneEnd: null, semesterTwoStart: null, diff --git a/packages/app/src/types/store.ts b/packages/app/src/types/store.ts index 68ae523..1e98df5 100755 --- a/packages/app/src/types/store.ts +++ b/packages/app/src/types/store.ts @@ -86,6 +86,7 @@ export interface DatesState { noSchool: Date[]; earlyDismissal: Date[]; lateStart: Date[]; + wednesday: Date[]; semesterOneStart: Date | null; semesterOneEnd: Date | null; semesterTwoStart: Date | null; @@ -96,6 +97,7 @@ export interface SerializedDatesState { noSchool: string[]; earlyDismissal: string[]; lateStart: string[]; + wednesday: string[]; semesterOneStart: string | null; semesterOneEnd: string | null; semesterTwoStart: string | null; diff --git a/packages/app/src/utils/process-info.ts b/packages/app/src/utils/process-info.ts index b02f456..7fa20ed 100755 --- a/packages/app/src/utils/process-info.ts +++ b/packages/app/src/utils/process-info.ts @@ -1,7 +1,7 @@ import { load } from 'react-native-cheerio'; import { DateType, DateSchema } from '@whs/server'; -import { fetch } from './utils'; +import { fetch, isResponseOk } from './utils'; import { processSchedule } from './process-schedule'; import { HEADER_SELECTOR, STUDENT_OVERVIEW_SELECTOR, STUDENT_ID_SELECTOR, @@ -23,7 +23,8 @@ export async function parseHTMLFromURL(url: string, options?: RequestInit) { timeout: FETCH_TIMEOUT, ...options, }); - if (!response.ok) { + // includes both ok and redirected + if (!isResponseOk(response)) { throw new NetworkError(); } const html = await response.text(); @@ -119,7 +120,7 @@ export async function fetchTeachersFromQuery(query: string, username: string, pa timeout: FETCH_TIMEOUT, signal, }); - if (!response.ok) { + if (!isResponseOk(response)) { throw new NetworkError(); } return response.json(); diff --git a/packages/app/src/utils/query-schedule.ts b/packages/app/src/utils/query-schedule.ts index dfbafc3..596afd1 100644 --- a/packages/app/src/utils/query-schedule.ts +++ b/packages/app/src/utils/query-schedule.ts @@ -172,7 +172,7 @@ export function getScheduleTypeOnDate(queryDate: Date, dates: DatesState, omitBr return 'WEEKEND'; } - if (day === 3) { + if (day === 3 || containsDate(queryDate, dates.wednesday)) { return 'WEDNESDAY'; } return 'REGULAR'; diff --git a/packages/app/src/utils/store.ts b/packages/app/src/utils/store.ts index e0b72ab..3eeba51 100644 --- a/packages/app/src/utils/store.ts +++ b/packages/app/src/utils/store.ts @@ -12,6 +12,7 @@ import { } from '../types/store'; import rootReducer from '../reducers/root'; import { reportNotEnoughSpace } from './utils'; +import datesReducer from '../reducers/dates'; // Do not persist the profile-photo, it will be manually rehydrated const profilePhotoTransform = createTransform( @@ -67,6 +68,11 @@ const dateTransform = createTransform( const migrations = { // v-1 (WHS v1 and v2) --> v3 3: () => rootReducer(undefined, { type: MiscellaneousActions.OTHER }), + // add wednesday option to DatesState + 4: (state: AppState) => ({ + ...state, + dates: datesReducer(undefined, { type: MiscellaneousActions.OTHER }), + }), }; const persistConfig = { diff --git a/packages/app/src/utils/utils.ts b/packages/app/src/utils/utils.ts index 739dcb0..9787d7a 100644 --- a/packages/app/src/utils/utils.ts +++ b/packages/app/src/utils/utils.ts @@ -1,6 +1,6 @@ import { Alert } from 'react-native'; import { subDays, format } from 'date-fns'; -import fetchPolyfill from 'react-native-fetch-polyfill'; +import fetchPolyfill, { Timeout } from 'react-native-fetch-polyfill'; import debounce from 'lodash.debounce'; import client from './bugsnag'; @@ -89,6 +89,14 @@ export function last(arr: T[]) { return arr.slice(-1)[0]; } +/** + * Returns true if status between 200 and 308 inclusive + * @param response to check + */ +export function isResponseOk(response: Response) { + return response.status >= 200 && response.status <= 308; +} + /** * Same signature as WHATWG fetch but rethrows TypeError as NetworkError for catching */ From 1d475f130f790fc36cd425e810d1897767dee139 Mon Sep 17 00:00:00 2001 From: Andrew Li Date: Thu, 14 Nov 2019 23:28:33 -0600 Subject: [PATCH 2/3] Linting errors --- packages/app/src/components/schedule/ScheduleCard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/app/src/components/schedule/ScheduleCard.tsx b/packages/app/src/components/schedule/ScheduleCard.tsx index 2087716..e2b9427 100644 --- a/packages/app/src/components/schedule/ScheduleCard.tsx +++ b/packages/app/src/components/schedule/ScheduleCard.tsx @@ -15,7 +15,7 @@ import { ClassItem, CrossSectionedItem, ScheduleItem, DaySchedule, ModNumber } f import { AppState } from '../../types/store'; import { getScheduleTypeOnDate, getModAtTime, isHalfMod, convertTimeToDate } from '../../utils/query-schedule'; import * as SCHEDULES from '../../constants/schedules'; -import { interpolateAssembly, getFinalsSchedule, createClassItem, injectAssemblyOrFinalsIfNeeded } from '../../utils/process-schedule'; +import { createClassItem, injectAssemblyOrFinalsIfNeeded } from '../../utils/process-schedule'; import ClassCardItem from './ClassCardItem'; import CrossSectionedCardItem from './CrossSectionedCardItem'; import Subtext from '../common/Subtext'; From 2a6896a8f552e02f1f9b9b298cdcb311c9dee20e Mon Sep 17 00:00:00 2001 From: Andrew Li Date: Thu, 14 Nov 2019 23:29:44 -0600 Subject: [PATCH 3/3] Bump version --- packages/app/src/utils/bugsnag.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/app/src/utils/bugsnag.ts b/packages/app/src/utils/bugsnag.ts index 1136d9f..f62240a 100644 --- a/packages/app/src/utils/bugsnag.ts +++ b/packages/app/src/utils/bugsnag.ts @@ -29,7 +29,7 @@ function serializeState(state: AppState): IMetadata { } const config = new Configuration(); -config.codeBundleId = '3.0.1-b3'; +config.codeBundleId = '3.0.1-b4'; config.notifyReleaseStages = ['production']; config.registerBeforeSendCallback((report) => { const state = store.getState();