{"version":3,"sources":["store/Configuration.ts","RestHelper.ts","store/Login.ts","store/ChallengeList.ts","store/ChallengeDetails.ts","store/UploadChallengeGpx.ts","store/UploadEffortGpx.ts","store/index.ts","components/LoginButton.tsx","components/LogoutButton.tsx","components/GetUserDetails.tsx","components/Layout.tsx","components/ChallengeList.tsx","components/Home.tsx","components/JoinButton.tsx","components/EffortList.tsx","components/UploadChallengeGpx.tsx","components/NoEffortList.tsx","components/UploadEffortGpx.tsx","components/ChallengeDetails.tsx","App.tsx","registerServiceWorker.ts","index.tsx","store/configureStore.ts"],"names":["initialState","siteTitle","apiBaseUrl","hasContent","response","contentLength","headers","get","Number","generateErrorMessage","resource","status","statusText","detail","getLoggedInUser","id_token","name","cookies","decodeURIComponent","document","cookie","split","trimLeft","indexOf","substring","length","getCookie","loggedInUser","jwt","decode","user_data","JSON","parse","actionCreators","setUserProfile","profile","dispatch","getState","appState","fetch","config","method","credentials","body","stringify","then","a","ok","RestHelper","type","message","text","console","error","catch","undefined","ChallengeType","requestChallengeList","challengeList","requestPending","challenges","json","data","ChallengeDetailActions","getSelectedChallenge","selectedChallenge","filter","c","onSelectedChallengeChanged","challengeDetails","selectedChallengeName","SelectedChallengeChanged","CurrentChallengeChanged","currentChallenge","ChallengeListStore","login","RegistrationStatusReceived","registrationStatus","registered","ServerRequestError","AgeGroupsReceived","ageGroups","EffortsReceived","efforts","AthletesReceived","athletes","selectedCategoryChanged","selectedCategory","SelectedCategoryChanged","joinChallenge","log","description","UploadChallengeGpxActions","onFileSelected","event","target","files","ChallengeGpxFileSelected","selectedFile","uploadFile","uploadChallengeGpx","ChallengeGpxFileUploadStarted","formData","FormData","append","ChallengeGpxFileUploaded","cancelUpload","ChallengeGpxFileUploadCanceled","UploadEffortGpxActions","onAthleteIdChanged","value","EffortGpxAthleteIdChanged","athleteId","EffortGpxFileSelected","uploadEffortGpx","EffortGpxFileUploadStarted","EffortGpxFileUploaded","EffortGpxFileUploadCanceled","reducers","state","action","isLoggedInAction","isErrorSettingProfileAction","errorSettingProfile","isSetConfigurationAction","incomingAction","requestError","registrationStatusReceived","isAthleteRegistered","ageGroupsReceivedAction","effortsReceivedAction","allEfforts","athletesReceivedAction","allAthletes","errorMessage","uploading","uploaded","connect","props","href","className","months","maxBirthYear","Date","getFullYear","minBirthYear","yearArray","y","push","GetUserDetails","React","constructor","super","birthDateString","birth_date","birthDateUtc","this","year","getUTCFullYear","month","getUTCMonth","day","getUTCDate","gender","email","handleYearChanged","bind","handleMonthChanged","handleDayChanged","handleGenderChanged","handleEmailChanged","render","onChange","map","m","i","Array","getDate","_","title","id","disabled","onClick","saveProfile","setState","birthDate","LoginStore","to","siteLogo","src","width","height","alt","children","siteFooter","ChallengeList","componentDidMount","renderChallengeListTable","renderLoadingIndicator","challenge","endDate","displayName","moment","startDate","format","fromNow","JoinButton","ChallengeDetails","toTimeFormat","duration","str","seconds","slice","asMinutes","minutes","asHours","hours","asDays","Math","floor","EffortList","renderEffortListTable","challengeType","showCategory","maximumAge","showLapCount","MostLaps","effort","athleteName","getCategory","athleteAge","athleteGender","lapCount","isKOM","elapsedTime","ageGroup","UploadChallengeGpx","sectionBody","e","UploadChallengeGpxStore","NoEffortList","renderNoEffortListTable","athletesWithEffort","Set","athletesWithNoEfforts","has","athlete","is_admin","age","UploadEffortGpx","fileInputRow","UploadEffortGpxStore","match","params","challengeName","componentDidUpdate","bestEffort","sub","renderChallengeDetails","renderNotFound","segmentId","pathname","location","hash","ChallengeDetailStore","exact","path","component","Home","isLocalhost","Boolean","window","hostname","register","navigator","URL","process","toString","origin","addEventListener","swUrl","contentType","serviceWorker","ready","registration","unregister","reload","registerValidSW","checkValidServiceWorker","onupdatefound","installingWorker","installing","onstatechange","controller","baseUrl","getElementsByTagName","getAttribute","history","createBrowserHistory","basename","resp","startsWith","warn","err","stack","REACT_APP_SITE_TITLE","REACT_APP_SITE_LOGO","REACT_APP_SITE_FOOTER","REACT_APP_API_BASE_URL","store","middleware","thunk","routerMiddleware","rootReducer","combineReducers","router","connectRouter","enhancers","windowIfDefined","__REDUX_DEVTOOLS_EXTENSION__","createStore","compose","applyMiddleware","configureStore","ReactDOM","App","getElementById","registerServiceWorker"],"mappings":"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","file":"static/js/main.681ca3c9.chunk.js","sourcesContent":["import {Action, AnyAction, Reducer} from 'redux';\n\nexport interface ConfigurationState {\n siteTitle: string,\n siteLogo?: string,\n siteFooter?: string,\n apiBaseUrl: string\n}\n\nexport interface SetConfigurationAction {\n type: 'SET_CONFIGURATION',\n config: ConfigurationState\n}\n\nfunction isSetConfigurationAction(action: Action): action is SetConfigurationAction {\n return action.type === 'SET_CONFIGURATION';\n}\n\nconst initialState = { siteTitle: 'Strava Segment Challenge', apiBaseUrl: '' } as ConfigurationState;\n\nexport const reducer: Reducer = (state: ConfigurationState | undefined, action: AnyAction) => {\n state = state || initialState;\n\n if (isSetConfigurationAction(action)) {\n return { ...state, config: action.config };\n }\n\n return state;\n};\n","import jwt from \"jwt-simple\";\n\nexport function hasContent(response: Response) {\n const contentLength = response.headers.get('Content-Length');\n\n return contentLength && Number(contentLength) > 0;\n}\n\nexport function generateErrorMessage(resource: string, status: number, statusText: string, detail: string) {\n if (status >= 500 && status < 600) {\n return `The ${resource} is currently unavailable. Please try again later or contact the webmaster if the problem persists. Error detail: ${detail}`;\n } else {\n return `An error occurred fetching or setting the ${resource}. Please contact the webmaster. Error detail: ${detail}`;\n }\n}\n\nfunction getCookie(name: string): string | undefined {\n let cookies = decodeURIComponent(document.cookie);\n for (let cookie of cookies.split(';')) {\n cookie = cookie.trimLeft();\n if (cookie.indexOf(name) === 0) {\n return cookie.substring(name.length + 1, cookie.length);\n }\n }\n\n return undefined;\n}\n\nexport function getLoggedInUser() {\n const id_token = getCookie('id_token');\n let loggedInUser = undefined;\n if (id_token) {\n loggedInUser = jwt.decode(id_token, '', true);\n\n if (typeof loggedInUser.user_data === \"string\") {\n loggedInUser.user_data = JSON.parse(loggedInUser.user_data);\n }\n }\n return loggedInUser;\n}\n","import {Action, AnyAction, Reducer} from 'redux';\nimport {AppThunkAction} from \"./index\";\nimport {generateErrorMessage, hasContent} from \"../RestHelper\";\nimport * as RestHelper from '../RestHelper';\n\nexport interface LoginInfo {\n sub: string,\n name: string,\n user_data: { profile_picture?: string, birth_date?: string, gender?: string, email?: string, is_admin?: boolean },\n nbf: number,\n exp: number,\n iat: number,\n iss: string,\n aud: string\n}\n\nexport interface LoginState {\n loggedInUser: LoginInfo | undefined,\n errorSettingProfile?: string\n}\n\nexport interface LoggedInAction {\n type: 'LOGGED_IN',\n loggedInUser: LoginInfo\n}\n\nexport interface ErrorSettingProfileAction {\n type: 'ERROR_SETTING_USER_PROFILE',\n message: string\n}\n\nfunction isLoggedInAction(action: Action): action is LoggedInAction {\n return action.type === 'LOGGED_IN';\n}\n\nfunction isErrorSettingProfileAction(action: Action): action is ErrorSettingProfileAction {\n return action.type === 'ERROR_SETTING_USER_PROFILE';\n}\n\ntype KnownAction = LoggedInAction | ErrorSettingProfileAction\n\nexport const actionCreators = {\n setUserProfile: (profile: { birthDate: Date, gender: string, email?: string }): AppThunkAction => (dispatch, getState) => {\n let appState = getState();\n fetch(\n `${appState.config.apiBaseUrl}api/athletes/self`,\n {\n method: 'POST',\n credentials: 'same-origin',\n body: JSON.stringify(profile),\n headers: {'Content-Type': 'application/json'}\n })\n .then(async response => {\n if (response.ok) {\n // check cookie\n let loggedInUser = RestHelper.getLoggedInUser();\n\n if (loggedInUser) {\n dispatch({\n type: 'LOGGED_IN',\n loggedInUser\n });\n } else {\n dispatch({\n type: 'ERROR_SETTING_USER_PROFILE',\n message: 'Failed to update user profile.'\n });\n }\n } else {\n let detail: string;\n if (hasContent(response)) {\n detail = await response.text();\n } else {\n detail = 'Unknown';\n }\n\n console.error(`Error updating user profile. Status: ${response.status}, Status Description: ${response.statusText}, Detail: ${detail}`);\n\n dispatch({\n type: 'ERROR_SETTING_USER_PROFILE',\n message: generateErrorMessage('user profile', response.status, response.statusText, detail)\n });\n }\n })\n .catch(error => {\n dispatch({\n type: 'ERROR_SETTING_USER_PROFILE',\n message: error\n })\n });\n }\n};\n\nconst initialState = {loggedInUser: undefined} as LoginState;\n\nexport const reducer: Reducer = (state: LoginState | undefined, action: AnyAction) => {\n state = state || initialState;\n\n if (isLoggedInAction(action)) {\n return {...state, loggedInUser: action.loggedInUser};\n } else if (isErrorSettingProfileAction(action)) {\n return {...state, errorSettingProfile: action.message};\n }\n\n return state;\n};\n","import {AnyAction, Reducer} from \"redux\";\nimport {AppThunkAction} from \"./index\";\nimport {generateErrorMessage, hasContent} from \"../RestHelper\"\n\nexport interface Challenge {\n id: number,\n name: string,\n displayName: string,\n description: string,\n segmentId: string,\n startDate: Date,\n endDate: Date,\n type: ChallengeType,\n}\n\nexport enum ChallengeType {\n Fastest = 0,\n MostLaps = 1\n}\n\nexport interface ChallengeListState {\n challenges?: Challenge[],\n requestPending: boolean,\n requestError?: string\n}\n\nexport interface RequestChallengeListAction {\n type: 'REQUEST_CHALLENGE_LIST';\n}\n\nexport interface ReceiveChallengeListAction {\n type: 'RECEIVE_CHALLENGE_LIST';\n challenges: Challenge[];\n}\n\nexport interface ErrorFetchingChallengeListAction {\n type: 'ERROR_FETCHING_CHALLENGE_LIST';\n message: string;\n}\n\ntype KnownAction = RequestChallengeListAction | ReceiveChallengeListAction | ErrorFetchingChallengeListAction;\n\nexport const actionCreators = {\n requestChallengeList: (): AppThunkAction => (dispatch, getState) => {\n const appState = getState();\n // If there is no request pending, and we have not previously fetched challenges, fetch the challenge list\n if (appState && (!appState.challengeList || (!appState.challengeList.requestPending && !appState.challengeList.challenges))) {\n fetch(`${appState.config.apiBaseUrl}api/challenges`)\n .then(async response => {\n if (response.ok) {\n const data = await response.json();\n dispatch({ type: 'RECEIVE_CHALLENGE_LIST', challenges: data as Challenge[] });\n } else {\n let detail : string;\n if (hasContent(response)) {\n detail = await response.text();\n } else {\n detail = 'Unknown';\n }\n\n console.error(`Error fetching challenge list. Status: ${response.status}, Status Description: ${response.statusText}, Detail: ${detail}`);\n\n dispatch({\n type: 'ERROR_FETCHING_CHALLENGE_LIST',\n message: generateErrorMessage('challenge list', response.status, response.statusText, detail)\n });\n }\n })\n .catch(error => {\n dispatch({\n type: 'ERROR_FETCHING_CHALLENGE_LIST',\n message: error\n })\n });\n\n dispatch({ type: 'REQUEST_CHALLENGE_LIST'});\n }\n }\n};\n\nconst initialState: ChallengeListState = { requestPending: false };\n\nexport const reducer: Reducer = (state: ChallengeListState | undefined, incomingAction: AnyAction): ChallengeListState => {\n state = state || initialState;\n\n const action = incomingAction as KnownAction;\n switch (action.type) {\n case 'REQUEST_CHALLENGE_LIST':\n if (!state.requestPending && !state.challenges) {\n return {...state, requestPending: true};\n } else {\n // Ignore redundant requests\n return state;\n }\n case 'RECEIVE_CHALLENGE_LIST':\n return {\n ...state,\n requestPending: false,\n challenges: (incomingAction as ReceiveChallengeListAction).challenges\n };\n case 'ERROR_FETCHING_CHALLENGE_LIST':\n return {\n ...state,\n requestPending: false,\n challenges: [],\n requestError: (incomingAction as ErrorFetchingChallengeListAction).message\n };\n default:\n return state;\n }\n};\n","import * as ChallengeListStore from \"./ChallengeList\";\nimport {AppThunkAction} from \"./index\";\nimport {AnyAction, Reducer} from \"redux\";\nimport {generateErrorMessage, hasContent} from \"../RestHelper\";\n\nexport interface AgeGroup {\n maximumAge: number,\n description: string\n}\n\nexport interface Effort {\n id: number,\n athleteId: number,\n athleteName: number\n athleteGender: string,\n athleteAge: number,\n activityId: number,\n lapCount: number,\n elapsedTime: number,\n isKOM: boolean\n}\n\nexport interface Athlete {\n id: number,\n displayName: string,\n gender: string,\n age: number\n}\n\nexport type Category = { minimumAge?: number, maximumAge?: number, gender?: string, description: string };\n\nexport interface ChallengeDetailsState {\n selectedChallengeName?: string,\n currentChallenge?: ChallengeListStore.Challenge,\n isAthleteRegistered?: boolean,\n selectedCategory: Category,\n ageGroups?: AgeGroup[],\n allEfforts?: Effort[],\n allAthletes?: Athlete[],\n errorMessage?: string\n}\n\n\nexport enum ChallengeDetailActions {\n SelectedChallengeChanged = 'SELECTED_CHALLENGE_CHANGED',\n CurrentChallengeChanged = 'CURRENT_CHALLENGE_CHANGED',\n SelectedCategoryChanged = 'SELECTED_CATEGORY_CHANGED',\n RegistrationStatusReceived = 'REGISTRATION_STATUS_RECEIVED',\n AgeGroupsReceived = 'AGE_GROUPS_RECEIVED',\n EffortsReceived = 'EFFORTS_RECEIVED',\n AthletesReceived = 'ATHLETES_RECEIVED',\n ServerRequestError = 'ERROR_FETCHING_DATA'\n}\n\nexport interface SelectedChallengeChanged {\n type: ChallengeDetailActions.SelectedChallengeChanged,\n selectedChallengeName: string | undefined\n}\n\nexport interface SelectedCategoryChanged {\n type: ChallengeDetailActions.SelectedCategoryChanged,\n selectedCategory: Category\n}\n\nexport interface CurrentChallengeChanged {\n type: ChallengeDetailActions.CurrentChallengeChanged,\n currentChallenge: ChallengeListStore.Challenge | undefined\n}\n\nexport interface RegistrationStatusReceived {\n type: ChallengeDetailActions.RegistrationStatusReceived,\n selectedChallengeName: string,\n registrationStatus: boolean\n}\n\nexport interface AgeGroupsReceived {\n type: ChallengeDetailActions.AgeGroupsReceived,\n selectedChallengeName: string,\n ageGroups: AgeGroup[]\n}\n\nexport interface EffortsReceived {\n type: ChallengeDetailActions.EffortsReceived,\n selectedChallengeName: string,\n efforts: Effort[]\n}\n\nexport interface AthletesReceived {\n type: ChallengeDetailActions.AthletesReceived,\n selectedChallengeName: string,\n athletes: Athlete[]\n}\n\nexport interface HasMessage {\n message: string\n}\n\nexport interface ServerRequestError extends HasMessage {\n type: ChallengeDetailActions.ServerRequestError\n}\n\ntype KnownAction =\n SelectedChallengeChanged\n | CurrentChallengeChanged\n | SelectedCategoryChanged\n | RegistrationStatusReceived\n | AgeGroupsReceived\n | EffortsReceived\n | AthletesReceived\n | ServerRequestError\n | ChallengeListStore.RequestChallengeListAction\n | ChallengeListStore.ReceiveChallengeListAction\n | ChallengeListStore.ErrorFetchingChallengeListAction;\n\nfunction getSelectedChallenge(challenges: ChallengeListStore.Challenge[], selectedChallenge: string): ChallengeListStore.Challenge | undefined {\n return challenges.filter(c => c.name === selectedChallenge)[0];\n}\n\nexport const actionCreators = {\n onSelectedChallengeChanged: (selectedChallenge: string): AppThunkAction => (dispatch, getState) => {\n let appState = getState();\n\n if (appState) {\n if (!appState.challengeDetails || selectedChallenge !== appState.challengeDetails.selectedChallengeName) {\n dispatch({\n type: ChallengeDetailActions.SelectedChallengeChanged,\n selectedChallengeName: selectedChallenge\n });\n\n if (!appState.challengeList || !appState.challengeList.challenges) {\n // Need to wait for challenge list\n ChallengeListStore.actionCreators.requestChallengeList()(dispatch, getState);\n } else {\n // The easy way, we already have the challenge list\n dispatch({\n type: ChallengeDetailActions.CurrentChallengeChanged,\n currentChallenge: getSelectedChallenge(appState.challengeList.challenges, selectedChallenge)\n });\n }\n\n if (appState.login?.loggedInUser) {\n // Fetch Registration Status\n fetch(`${appState.config.apiBaseUrl}api/challenges/${selectedChallenge}/registration`, {credentials: 'same-origin'})\n .then(async response => {\n if (response.ok) {\n const data = await response.json();\n dispatch({\n type: ChallengeDetailActions.RegistrationStatusReceived,\n selectedChallengeName: selectedChallenge,\n registrationStatus: data.registered\n });\n } else {\n let detail: string;\n if (hasContent(response)) {\n detail = await response.text();\n } else {\n detail = 'Unknown';\n }\n\n console.error(`Error fetching registration status. Status: ${response.status}, Status Description: ${response.statusText}, Detail: ${detail}`);\n\n dispatch({\n type: ChallengeDetailActions.ServerRequestError,\n message: generateErrorMessage('registration status', response.status, response.statusText, detail)\n });\n }\n })\n .catch(error => {\n dispatch({\n type: ChallengeDetailActions.ServerRequestError,\n message: error\n })\n });\n }\n\n // Fetch Age Groups\n fetch(`${appState.config.apiBaseUrl}api/challenges/${selectedChallenge}/age_groups`)\n .then(async response => {\n if (response.ok) {\n const data = await response.json();\n dispatch({\n type: ChallengeDetailActions.AgeGroupsReceived,\n selectedChallengeName: selectedChallenge,\n ageGroups: data\n });\n } else {\n let detail: string;\n if (hasContent(response)) {\n detail = await response.text();\n } else {\n detail = 'Unknown';\n }\n\n console.error(`Error fetching age groups. Status: ${response.status}, Status Description: ${response.statusText}, Detail: ${detail}`);\n\n dispatch({\n type: ChallengeDetailActions.ServerRequestError,\n message: generateErrorMessage('challenge age groups', response.status, response.statusText, detail)\n });\n }\n })\n .catch(error => {\n dispatch({\n type: ChallengeDetailActions.ServerRequestError,\n message: error\n })\n });\n\n // Fetch Efforts\n fetch(`${appState.config.apiBaseUrl}api/challenges/${selectedChallenge}/efforts`)\n .then(async response => {\n if (response.ok) {\n const data = await response.json();\n dispatch({\n type: ChallengeDetailActions.EffortsReceived,\n selectedChallengeName: selectedChallenge,\n efforts: data\n });\n } else {\n let detail: string;\n if (hasContent(response)) {\n detail = await response.text();\n } else {\n detail = 'Unknown';\n }\n\n console.error(`Error fetching efforts. Status: ${response.status}, Status Description: ${response.statusText}, Detail: ${detail}`);\n\n dispatch({\n type: ChallengeDetailActions.ServerRequestError,\n message: generateErrorMessage('efforts', response.status, response.statusText, detail)\n });\n }\n })\n .catch(error => {\n dispatch({\n type: ChallengeDetailActions.ServerRequestError,\n message: error\n })\n });\n\n // Fetch Athletes\n fetch(`${appState.config.apiBaseUrl}api/challenges/${selectedChallenge}/athletes`)\n .then(async response => {\n if (response.ok) {\n const data = await response.json();\n dispatch({\n type: ChallengeDetailActions.AthletesReceived,\n selectedChallengeName: selectedChallenge,\n athletes: data\n });\n } else {\n let detail: string;\n if (hasContent(response)) {\n detail = await response.text();\n } else {\n detail = 'Unknown';\n }\n\n console.error(`Error fetching athletes. Status: ${response.status}, Status Description: ${response.statusText}, Detail: ${detail}`);\n\n dispatch({\n type: ChallengeDetailActions.ServerRequestError,\n message: generateErrorMessage('athletes', response.status, response.statusText, detail)\n });\n }\n })\n .catch(error => {\n dispatch({\n type: ChallengeDetailActions.ServerRequestError,\n message: error\n })\n });\n }\n }\n },\n selectedCategoryChanged: (selectedCategory: Category) => ({\n type: ChallengeDetailActions.SelectedCategoryChanged,\n selectedCategory: selectedCategory\n } as SelectedCategoryChanged),\n joinChallenge: (): AppThunkAction => (dispatch, getState) => {\n let appState = getState();\n\n if (appState) {\n const selectedChallenge = appState.challengeDetails?.selectedChallengeName;\n if (selectedChallenge && appState.login?.loggedInUser) {\n fetch(`${appState.config.apiBaseUrl}api/challenges/${selectedChallenge}/register`, {method: 'POST', credentials: 'same-origin'})\n .then(async response => {\n if (response.ok) {\n const data = await response.json();\n dispatch({\n type: ChallengeDetailActions.RegistrationStatusReceived,\n selectedChallengeName: selectedChallenge,\n registrationStatus: data.registered\n });\n\n // Immediately initiate a refresh\n fetch(`${appState.config.apiBaseUrl}api/challenges/${selectedChallenge}/refresh`, {method: 'POST', credentials: 'same-origin'})\n .then(response => {\n if (response.ok) {\n console.log('Refresh started.');\n } else {\n console.log(`Refresh failed to start: ${response.status}`)\n }\n });\n } else {\n let detail: string;\n if (hasContent(response)) {\n detail = await response.text();\n } else {\n detail = 'Unknown';\n }\n\n console.error(`Error updating registration status. Status: ${response.status}, Status Description: ${response.statusText}, Detail: ${detail}`);\n\n dispatch({\n type: ChallengeDetailActions.ServerRequestError,\n message: generateErrorMessage('registration status', response.status, response.statusText, detail)\n });\n }\n })\n .catch(error => {\n dispatch({\n type: ChallengeDetailActions.ServerRequestError,\n message: error\n })\n });\n }\n }\n }\n};\n\nconst initialState: ChallengeDetailsState = {selectedCategory: {description: 'Overall'}};\n\nexport const reducer: Reducer =\n (state: ChallengeDetailsState | undefined, incomingAction: AnyAction) => {\n state = state || initialState;\n\n const action = incomingAction as KnownAction;\n\n switch (action.type) {\n case ChallengeDetailActions.SelectedChallengeChanged:\n // Is this ok? Do we have to null out things individually?\n return {\n ...initialState,\n selectedChallengeName: (action as SelectedChallengeChanged).selectedChallengeName,\n };\n case ChallengeDetailActions.CurrentChallengeChanged:\n return {...state, currentChallenge: (action as CurrentChallengeChanged).currentChallenge};\n case 'RECEIVE_CHALLENGE_LIST':\n if (state.selectedChallengeName) {\n return {\n ...state,\n currentChallenge:\n getSelectedChallenge(\n (action as ChallengeListStore.ReceiveChallengeListAction).challenges,\n state.selectedChallengeName\n )\n };\n }\n\n break;\n case ChallengeDetailActions.RegistrationStatusReceived:\n const registrationStatusReceived = action as RegistrationStatusReceived;\n if (registrationStatusReceived.selectedChallengeName === state.selectedChallengeName) {\n return {...state, isAthleteRegistered: registrationStatusReceived.registrationStatus};\n }\n\n break;\n case ChallengeDetailActions.AgeGroupsReceived:\n const ageGroupsReceivedAction = action as AgeGroupsReceived;\n if (ageGroupsReceivedAction.selectedChallengeName === state.selectedChallengeName) {\n return {...state, ageGroups: ageGroupsReceivedAction.ageGroups};\n }\n\n break;\n case ChallengeDetailActions.EffortsReceived:\n const effortsReceivedAction = action as EffortsReceived;\n if (effortsReceivedAction.selectedChallengeName === state.selectedChallengeName) {\n return {...state, allEfforts: effortsReceivedAction.efforts};\n }\n\n break;\n case ChallengeDetailActions.AthletesReceived:\n const athletesReceivedAction = action as AthletesReceived;\n if (athletesReceivedAction.selectedChallengeName === state.selectedChallengeName) {\n return {...state, allAthletes: athletesReceivedAction.athletes};\n }\n\n break;\n case ChallengeDetailActions.ServerRequestError:\n case \"ERROR_FETCHING_CHALLENGE_LIST\":\n return {...state, errorMessage: (action as HasMessage).message};\n }\n\n return state;\n };\n","import {AnyAction, Reducer} from \"redux\";\n\nimport {HasMessage} from \"./ChallengeDetails\";\nimport {ChangeEvent} from \"react\";\nimport {AppThunkAction} from \"./index\";\nimport {generateErrorMessage, hasContent} from \"../RestHelper\";\n\nexport interface UploadChallengeGpxState {\n selectedFile?: File | null,\n uploading?: boolean,\n uploaded?: boolean,\n errorMessage?: string,\n}\n\nexport enum UploadChallengeGpxActions {\n ChallengeGpxFileSelected = 'CHALLENGE_GPX_FILE_SELECTED',\n ChallengeGpxFileUploadCanceled = 'CHALLENGE_GPX_UPLOAD_CANCELED',\n ChallengeGpxFileUploadStarted = 'CHALLENGE_GPX_UPLOAD_STARTED',\n ChallengeGpxFileUploaded = 'CHALLENGE_GPX_UPLOAD_DONE',\n ServerRequestError = 'ERROR_FETCHING_DATA'\n}\n\nexport interface ChallengeGpxFileSelected {\n type: UploadChallengeGpxActions.ChallengeGpxFileSelected,\n selectedFile: File\n}\n\nexport interface ChallengeGpxFileUploadCanceled {\n type: UploadChallengeGpxActions.ChallengeGpxFileUploadCanceled\n}\n\nexport interface ChallengeGpxFileUploadStarted {\n type: UploadChallengeGpxActions.ChallengeGpxFileUploadStarted\n}\n\nexport interface ChallengeGpxFileUploaded {\n type: UploadChallengeGpxActions.ChallengeGpxFileUploaded\n}\n\nexport interface ServerRequestError extends HasMessage {\n type: UploadChallengeGpxActions.ServerRequestError\n}\n\nexport const actionCreators = {\n onFileSelected: (event: ChangeEvent): AppThunkAction => (dispatch, getState) => {\n if (event.target.files && event.target.files.length === 1) {\n dispatch({\n type: UploadChallengeGpxActions.ChallengeGpxFileSelected,\n selectedFile: event.target.files[0]\n });\n }\n },\n uploadFile: (): AppThunkAction => (dispatch, getState) => {\n let appState = getState();\n\n if (appState.uploadChallengeGpx?.selectedFile &&\n appState.challengeDetails?.selectedChallengeName) {\n\n dispatch({\n type: UploadChallengeGpxActions.ChallengeGpxFileUploadStarted\n });\n\n let formData = new FormData();\n formData.append('gpxFile', appState.uploadChallengeGpx.selectedFile);\n\n fetch(\n `${appState.config.apiBaseUrl}api/challenges/${appState.challengeDetails.selectedChallengeName}/set_gpx`,\n {method: 'POST', credentials: 'same-origin', body: formData})\n .then(async response => {\n if (response.ok) {\n dispatch({\n type: UploadChallengeGpxActions.ChallengeGpxFileUploaded\n });\n } else {\n let detail: string;\n if (hasContent(response)) {\n detail = await response.text();\n } else {\n detail = 'Unknown';\n }\n\n console.error(`Error uploading GPX data. Status: ${response.status}, Status Description: ${response.statusText}, Detail: ${detail}`);\n\n dispatch({\n type: UploadChallengeGpxActions.ServerRequestError,\n message: generateErrorMessage('registration status', response.status, response.statusText, detail)\n });\n }\n });\n } else {\n console.log('Unable to process uploadFile action. selectedFile is not available in app state.');\n }\n },\n cancelUpload: (): AppThunkAction => (dispatch, getState) => {\n dispatch({\n type: UploadChallengeGpxActions.ChallengeGpxFileUploadCanceled\n });\n }\n};\n\ntype KnownAction =\n ChallengeGpxFileSelected |\n ChallengeGpxFileUploadCanceled |\n ChallengeGpxFileUploadStarted |\n ChallengeGpxFileUploaded |\n ServerRequestError;\n\nconst initialState: UploadChallengeGpxState = {};\n\nexport const reducer: Reducer =\n (state: UploadChallengeGpxState | undefined, incomingAction: AnyAction) => {\n state = state || initialState;\n\n const action = incomingAction as KnownAction;\n\n switch (action.type) {\n case UploadChallengeGpxActions.ChallengeGpxFileSelected:\n return {\n ...state,\n selectedFile: (action as ChallengeGpxFileSelected).selectedFile,\n };\n\n case UploadChallengeGpxActions.ChallengeGpxFileUploadCanceled:\n return {\n ...state,\n selectedFile: null\n };\n\n case UploadChallengeGpxActions.ChallengeGpxFileUploadStarted:\n return {\n ...state,\n uploading: true\n };\n\n case UploadChallengeGpxActions.ChallengeGpxFileUploaded:\n return {\n ...state,\n uploading: false,\n uploaded: true\n };\n\n case UploadChallengeGpxActions.ServerRequestError:\n return {\n ...state,\n errorMessage: (action as HasMessage).message,\n selectedFile: null,\n uploading: false\n };\n }\n\n return state;\n };\n","import {AnyAction, Reducer} from \"redux\";\n\nimport {HasMessage} from \"./ChallengeDetails\";\nimport {ChangeEvent} from \"react\";\nimport {AppThunkAction} from \"./index\";\nimport {generateErrorMessage, hasContent} from \"../RestHelper\";\n\nexport interface UploadEffortGpxState {\n selectedFile?: File | null,\n athleteId?: string,\n uploading?: boolean,\n uploaded?: boolean,\n errorMessage?: string,\n}\n\nexport enum UploadEffortGpxActions {\n EffortGpxFileSelected = 'EFFORT_GPX_FILE_SELECTED',\n EffortGpxAthleteIdChanged = 'EFFORT_GPX_ATHLETE_ID_CHANGED',\n EffortGpxFileUploadCanceled = 'EFFORT_GPX_UPLOAD_CANCELED',\n EffortGpxFileUploadStarted = 'EFFORT_GPX_UPLOAD_STARTED',\n EffortGpxFileUploaded = 'EFFORT_GPX_UPLOAD_DONE',\n ServerRequestError = 'ERROR_FETCHING_DATA'\n}\n\nexport interface EffortGpxFileSelected {\n type: UploadEffortGpxActions.EffortGpxFileSelected,\n selectedFile: File\n}\n\nexport interface EffortGpxAthleteIdChanged {\n type: UploadEffortGpxActions.EffortGpxAthleteIdChanged,\n athleteId: string\n}\n\nexport interface EffortGpxFileUploadCanceled {\n type: UploadEffortGpxActions.EffortGpxFileUploadCanceled\n}\n\nexport interface EffortGpxFileUploadStarted {\n type: UploadEffortGpxActions.EffortGpxFileUploadStarted\n}\n\nexport interface EffortGpxFileUploaded {\n type: UploadEffortGpxActions.EffortGpxFileUploaded\n}\n\nexport interface ServerRequestError extends HasMessage {\n type: UploadEffortGpxActions.ServerRequestError\n}\n\nexport const actionCreators = {\n onAthleteIdChanged: (event: ChangeEvent): AppThunkAction => (dispatch, getState) => {\n console.log(`athlete id changing: ${event.target.value}`);\n dispatch({\n type: UploadEffortGpxActions.EffortGpxAthleteIdChanged,\n athleteId: event.target.value\n });\n },\n onFileSelected: (event: ChangeEvent): AppThunkAction => (dispatch, getState) => {\n if (event.target.files && event.target.files.length === 1) {\n dispatch({\n type: UploadEffortGpxActions.EffortGpxFileSelected,\n selectedFile: event.target.files[0]\n });\n }\n },\n uploadFile: (): AppThunkAction => (dispatch, getState) => {\n let appState = getState();\n\n if (appState.uploadEffortGpx?.selectedFile &&\n appState.challengeDetails?.selectedChallengeName) {\n\n dispatch({\n type: UploadEffortGpxActions.EffortGpxFileUploadStarted\n });\n\n let formData = new FormData();\n formData.append('gpxFile', appState.uploadEffortGpx.selectedFile);\n\n console.log(`upload gpx for: ${appState.uploadEffortGpx.athleteId}`)\n fetch(\n `${appState.config.apiBaseUrl}api/challenges/${appState.challengeDetails.selectedChallengeName}/upload_activity?athlete=${appState.uploadEffortGpx.athleteId}`,\n {method: 'POST', credentials: 'same-origin', body: formData})\n .then(async response => {\n if (response.ok) {\n dispatch({\n type: UploadEffortGpxActions.EffortGpxFileUploaded\n });\n } else {\n let detail: string;\n if (hasContent(response)) {\n detail = await response.text();\n } else {\n detail = 'Unknown';\n }\n\n console.error(`Error uploading GPX data. Status: ${response.status}, Status Description: ${response.statusText}, Detail: ${detail}`);\n\n dispatch({\n type: UploadEffortGpxActions.ServerRequestError,\n message: generateErrorMessage('registration status', response.status, response.statusText, detail)\n });\n }\n });\n } else {\n console.log('Unable to process uploadFile action. selectedFile is not available in app state.');\n }\n },\n cancelUpload: (): AppThunkAction => (dispatch, getState) => {\n dispatch({\n type: UploadEffortGpxActions.EffortGpxFileUploadCanceled\n });\n }\n};\n\ntype KnownAction =\n EffortGpxFileSelected |\n EffortGpxAthleteIdChanged |\n EffortGpxFileUploadCanceled |\n EffortGpxFileUploadStarted |\n EffortGpxFileUploaded |\n ServerRequestError;\n\nconst initialState: UploadEffortGpxState = {};\n\nexport const reducer: Reducer =\n (state: UploadEffortGpxState | undefined, incomingAction: AnyAction) => {\n state = state || initialState;\n\n const action = incomingAction as KnownAction;\n\n switch (action.type) {\n case UploadEffortGpxActions.EffortGpxFileSelected:\n return {\n ...state,\n selectedFile: (action as EffortGpxFileSelected).selectedFile,\n };\n\n case UploadEffortGpxActions.EffortGpxAthleteIdChanged:\n console.log(`athlete id changed: ${(action as EffortGpxAthleteIdChanged).athleteId}`);\n return {\n ...state,\n athleteId: (action as EffortGpxAthleteIdChanged).athleteId\n }\n\n case UploadEffortGpxActions.EffortGpxFileUploadCanceled:\n return {\n ...state,\n selectedFile: null\n };\n\n case UploadEffortGpxActions.EffortGpxFileUploadStarted:\n return {\n ...state,\n uploading: true\n };\n\n case UploadEffortGpxActions.EffortGpxFileUploaded:\n return {\n ...state,\n uploading: false,\n uploaded: true\n };\n\n case UploadEffortGpxActions.ServerRequestError:\n return {\n ...state,\n errorMessage: (action as HasMessage).message,\n selectedFile: null,\n uploading: false\n };\n }\n\n return state;\n };\n","import * as Configuration from './Configuration';\nimport * as Login from './Login';\nimport * as ChallengeList from \"./ChallengeList\";\nimport * as ChallengeDetails from \"./ChallengeDetails\";\nimport * as UploadChallengeGpx from \"./UploadChallengeGpx\";\nimport * as UploadEffortGpx from \"./UploadEffortGpx\";\n\n// The top-level state object\nexport interface ApplicationState {\n login?: Login.LoginState;\n config: Configuration.ConfigurationState;\n challengeList?: ChallengeList.ChallengeListState;\n challengeDetails?: ChallengeDetails.ChallengeDetailsState;\n uploadChallengeGpx?: UploadChallengeGpx.UploadChallengeGpxState;\n uploadEffortGpx?: UploadEffortGpx.UploadEffortGpxState;\n}\n\nexport const reducers = {\n login: Login.reducer,\n config: Configuration.reducer,\n challengeList: ChallengeList.reducer,\n challengeDetails: ChallengeDetails.reducer,\n uploadChallengeGpx: UploadChallengeGpx.reducer,\n uploadEffortGpx: UploadEffortGpx.reducer,\n};\n\n// This type can be used as a hint on action creators so that its 'dispatch' and 'getState' params are\n// correctly typed to match your store.\nexport interface AppThunkAction {\n (dispatch: (action: TAction) => void, getState: () => ApplicationState): void;\n}\n","import * as React from 'react';\nimport { connect } from 'react-redux';\nimport { ConfigurationState } from \"../store/Configuration\";\nimport { ApplicationState } from \"../store\";\n\nconst LoginButton = (props: { config: ConfigurationState }) => (\n Login With Strava\n);\n\nexport default connect((state: ApplicationState, props) =>\n ({ ...props, config: state.config }))(LoginButton);\n","import * as React from 'react';\nimport { connect } from 'react-redux';\nimport { ApplicationState } from \"../store\";\nimport { ConfigurationState } from \"../store/Configuration\";\n\nconst LogoutButton = (props: { config: ConfigurationState }) => (\n Logout\n);\n\nexport default connect((state: ApplicationState, props) =>\n ({ ...props, config: state.config }))(LogoutButton);\n","import * as React from 'react';\nimport {connect} from \"react-redux\";\nimport * as LoginStore from \"../store/Login\";\nimport {ApplicationState} from \"../store\";\nimport LogoutButton from \"./LogoutButton\";\nimport {ChangeEvent} from \"react\";\n\ntype GetUserDetailsProps =\n { login?: LoginStore.LoginState } &\n { setUserProfile: (profile: { birthDate: Date, gender: string, email?: string }) => void };\n\ntype GetUserDetailsState = {\n year?: number,\n // Index by 1 month. Fuck javascript.\n month?: number,\n day?: number,\n gender?: string,\n email?: string\n};\n\nconst months = [\n 'Jan',\n 'Feb',\n 'Mar',\n 'Apr',\n 'May',\n 'Jun',\n 'Jul',\n 'Aug',\n 'Sep',\n 'Oct',\n 'Nov',\n 'Dec'\n];\n\nconst maxBirthYear = new Date().getFullYear() - 13;\nconst minBirthYear = maxBirthYear - (99 - 13);\nlet yearArray: number[] = [];\nfor (let y = maxBirthYear; y >= minBirthYear; y--) {\n yearArray.push(y);\n}\n\nfunction getDaysPerMonth(year: number | undefined, month: number | undefined) {\n if (month) {\n // Note month here is index by 1, where as javascript is index by zero, which is why this works.\n if (year) {\n return new Date(year, month, 0).getDate();\n } else {\n // Intentionally choosing a leap year, since we want to include 29 for february\n return new Date(2020, month, 0).getDate();\n }\n } else {\n return 31;\n }\n}\n\nclass GetUserDetails extends React.PureComponent {\n constructor(props: GetUserDetailsProps) {\n super(props);\n\n const birthDateString = props.login?.loggedInUser?.user_data?.birth_date;\n const birthDateUtc = birthDateString ? new Date(birthDateString) : undefined;\n\n console.log(props.login?.loggedInUser);\n\n this.state = {\n year: birthDateUtc?.getUTCFullYear(),\n month: birthDateUtc ? birthDateUtc.getUTCMonth() + 1 : undefined,\n day: birthDateUtc?.getUTCDate(),\n gender: props.login?.loggedInUser?.user_data?.gender,\n email: props.login?.loggedInUser?.user_data?.email || ''\n }\n\n this.handleYearChanged = this.handleYearChanged.bind(this);\n this.handleMonthChanged = this.handleMonthChanged.bind(this);\n this.handleDayChanged = this.handleDayChanged.bind(this);\n this.handleGenderChanged = this.handleGenderChanged.bind(this);\n this.handleEmailChanged = this.handleEmailChanged.bind(this);\n }\n\n public render() {\n console.log(this.state);\n return (\n
\n
\n

Complete Profile

\n

In order to participate in challenges we need your birth date and gender.

\n
\n \n \n \n
\n
\n \n
\n
\n \n
\n
\n \n \n
\n
\n
\n );\n }\n\n private handleYearChanged(event: ChangeEvent) {\n this.setState({year: Number(event.target.value)});\n }\n\n private handleMonthChanged(event: ChangeEvent) {\n this.setState({month: Number(event.target.value)});\n }\n\n private handleDayChanged(event: ChangeEvent) {\n this.setState({day: Number(event.target.value)});\n }\n\n private handleGenderChanged(event: ChangeEvent) {\n this.setState({gender: event.target.value});\n }\n\n private handleEmailChanged(event: ChangeEvent) {\n this.setState({email: event.target.value});\n }\n\n private saveProfile() {\n if (this.state.year && this.state.month && this.state.day && this.state.gender) {\n this.props.setUserProfile({\n birthDate: new Date(this.state.year, this.state.month - 1, this.state.day),\n gender: this.state.gender,\n email: this.state.email\n });\n }\n }\n}\n\nexport default connect((state: ApplicationState) => ({login: state.login}), LoginStore.actionCreators)(GetUserDetails);\n","import * as React from 'react';\nimport {connect} from \"react-redux\";\nimport {Link} from \"react-router-dom\";\nimport LoginButton from \"./LoginButton\";\nimport LogoutButton from \"./LogoutButton\";\nimport GetUserDetails from \"./GetUserDetails\";\nimport {ApplicationState} from \"../store\";\nimport {ConfigurationState} from \"../store/Configuration\";\nimport {LoginState} from \"../store/Login\";\n\nconst Layout = (props: { children?: React.ReactNode, config: ConfigurationState, login?: LoginState }) => (\n \n
\n
\n

\n \n {props.config.siteLogo &&\n \"logo\"/}\n {props.config.siteTitle}\n \n

\n
\n
\n {(props.login && props.login.loggedInUser) ?\n Welcome, {props.login.loggedInUser.name} :\n }\n
\n
\n
\n {props.children}\n
\n {props.config.siteFooter &&
{props.config.siteFooter}
}\n {/* If the user is logged in, but has not yet set their birth date and email, display the user profile dialog. */}\n {props.login?.loggedInUser && !(props.login.loggedInUser.user_data.birth_date && props.login.loggedInUser.user_data.email) &&\n }\n
\n);\n\nexport default connect(\n (state: ApplicationState, props) =>\n ({...props, config: state.config, login: state.login}))(Layout);\n","import * as React from 'react';\nimport {connect, Matching} from 'react-redux';\nimport {Link} from \"react-router-dom\";\nimport moment from \"moment\";\nimport * as ChallengeListStore from '../store/ChallengeList'\nimport {ApplicationState} from \"../store\";\n\ntype ChallengeListProps =\n ChallengeListStore.ChallengeListState &\n { requestChallengeList: () => void };\n\nclass ChallengeList extends React.PureComponent> {\n public componentDidMount() {\n this.props.requestChallengeList();\n }\n\n public render() {\n return (\n \n {this.props.requestError &&\n {this.props.requestError}}\n {this.props.challenges ?\n ChallengeList.renderChallengeListTable(this.props.challenges) :\n ChallengeList.renderLoadingIndicator()}\n \n );\n }\n\n private static renderChallengeListTable(challenges: ChallengeListStore.Challenge[]) {\n return (\n \n \n \n \n \n \n \n \n \n {challenges.map((challenge: ChallengeListStore.Challenge) =>\n new Date()) ? 'active-challenge' : 'inactive-challenge'}>\n \n \n \n \n )}\n \n
SegmentStart DateEnd Date
{challenge.displayName}{moment(challenge.startDate).fromNow()}{moment(challenge.endDate).fromNow()}
\n );\n }\n\n private static renderLoadingIndicator() {\n return (\n
Loading ...
\n )\n }\n}\n\nexport default connect(\n (state: ApplicationState) => state.challengeList,\n ChallengeListStore.actionCreators\n)(ChallengeList);\n","import * as React from 'react';\nimport {connect} from 'react-redux';\nimport {ApplicationState} from \"../store\";\nimport ChallengeList from \"./ChallengeList\";\n\nconst Home = (state: ApplicationState) => (\n
\n

Challenges

\n \n
\n);\n\nexport default connect((state: ApplicationState) => state)(Home);\n","import * as React from 'react';\nimport {connect} from \"react-redux\";\nimport {ApplicationState} from \"../store\";\nimport * as ChallengeDetails from \"../store/ChallengeDetails\";\n\n\ntype JoinButtonProps =\n {joinChallenge: () => void}\n\nclass JoinButton extends React.PureComponent {\n public render() {\n return ();\n }\n}\nexport default connect((state: ApplicationState) => ({}), ChallengeDetails.actionCreators)(\n JoinButton\n);\n","import * as React from 'react';\nimport {connect, Matching} from \"react-redux\";\nimport * as ChallengeDetailsStore from \"../store/ChallengeDetails\";\nimport moment from \"moment\";\nimport {ApplicationState} from \"../store\";\nimport {ChallengeType} from \"../store/ChallengeList\";\n\ntype EffortListProps =\n ChallengeDetailsStore.ChallengeDetailsState;\n\nfunction toTimeFormat(duration: moment.Duration) {\n let str = ('0' + duration.seconds()).slice(-2);\n\n if (duration.asMinutes() >= 1.0) {\n str = `${('0' + duration.minutes()).slice(-2)}:${str}`;\n\n if (duration.asHours() >= 1.0) {\n str = `${('0' + duration.hours()).slice(-2)}:${str}`;\n\n if (duration.asDays() >= 1.0) {\n str = `${Math.floor(duration.asDays())} days ${str}`;\n }\n }\n } else {\n str += ' seconds';\n }\n\n return str;\n}\n\nclass EffortList extends React.PureComponent> {\n public render() {\n return (\n \n {this.props.errorMessage &&\n {this.props.errorMessage}}\n {this.props.allEfforts ?\n this.renderEffortListTable(this.props.currentChallenge?.type, this.props.allEfforts) :\n EffortList.renderLoadingIndicator()}\n \n );\n }\n\n private renderEffortListTable(challengeType: ChallengeType | undefined, efforts: ChallengeDetailsStore.Effort[]) {\n // TODO filter by category\n const showCategory = !(this.props.selectedCategory.maximumAge && this.props.selectedCategory.gender);\n const showLapCount = challengeType === ChallengeType.MostLaps;\n return (\n \n \n \n \n {showCategory && }\n {showLapCount && }\n \n \n \n \n {efforts.map((effort: ChallengeDetailsStore.Effort) =>\n \n \n {showCategory && }\n {showLapCount && }\n \n \n )}\n \n
AthleteCategoryLap CountTime
{effort.athleteName}{this.getCategory(effort.athleteAge, effort.athleteGender)}{effort.lapCount}{toTimeFormat(moment.duration(effort.elapsedTime, 'seconds'))}
\n );\n }\n\n private getCategory(athleteAge: number, athleteGender: string): string {\n if (this.props.ageGroups) {\n let gender = 'Other';\n switch (athleteGender) {\n case 'm':\n case 'M':\n gender = 'Men';\n break;\n case 'f':\n case 'F':\n gender = 'Women';\n break;\n }\n\n const ageGroup = this.props.ageGroups.filter(a => a.maximumAge >= athleteAge)[0];\n if (ageGroup) {\n return `${gender}, ${ageGroup.description}`;\n } else {\n return gender;\n }\n } else {\n return 'Unknown';\n }\n }\n\n private static renderLoadingIndicator() {\n return (\n
Loading ...
\n )\n }\n}\n\nexport default connect(\n (state: ApplicationState) => state.challengeDetails\n)(EffortList);\n","import * as React from \"react\";\nimport {connect, Matching} from \"react-redux\";\nimport {UploadChallengeGpxState} from \"../store/UploadChallengeGpx\";\nimport * as ChallengeDetailStore from \"../store/ChallengeDetails\";\nimport * as UploadChallengeGpxStore from \"../store/UploadChallengeGpx\";\nimport {LoginState} from \"../store/Login\";\nimport {ApplicationState} from \"../store\";\nimport {ChangeEvent} from \"react\";\n\ntype UploadChallengeProps =\n UploadChallengeGpxStore.UploadChallengeGpxState &\n ChallengeDetailStore.ChallengeDetailsState &\n { login?: LoginState } &\n {\n onFileSelected: (event: ChangeEvent) => void,\n uploadFile: () => void,\n cancelUpload: () => void\n };\n\nclass UploadChallengeGpx extends React.PureComponent, UploadChallengeGpxState> {\n constructor(props: UploadChallengeProps) {\n super(props);\n\n this.state = {};\n }\n\n public render() {\n let sectionBody;\n\n if (this.props.uploaded) {\n sectionBody = (\n
\n GPX data successfully uploaded.\n
\n );\n } else if (this.props.uploading) {\n sectionBody = (\n
\n Uploading File: {this.props.selectedFile?.name || \"unknown\"}\n
\n );\n } else if (this.props.errorMessage) {\n sectionBody = (\n
\n An error occurred: {this.props.errorMessage}\n
\n );\n } else if (this.props.selectedFile) {\n sectionBody = (\n
\n File selected: {this.props.selectedFile?.name}\n \n \n\n
\n );\n } else {\n sectionBody = (\n
\n this.props.onFileSelected(e)}/>\n
\n );\n }\n\n return (\n
\n

\n Upload Segment GPX Data\n

\n {sectionBody}\n
\n );\n }\n}\n\nexport default connect(\n (state: ApplicationState) => ({...state.uploadChallengeGpx, ...state.challengeDetails, login: state.login}),\n UploadChallengeGpxStore.actionCreators\n)(UploadChallengeGpx);\n","import * as React from 'react';\nimport {connect, Matching} from \"react-redux\";\nimport * as ChallengeDetailsStore from \"../store/ChallengeDetails\";\nimport {ApplicationState} from \"../store\";\nimport {LoginState} from \"../store/Login\";\n\ntype NoEffortListProps =\n ChallengeDetailsStore.ChallengeDetailsState &\n { login?: LoginState };\n\nclass NoEffortList extends React.PureComponent> {\n public render() {\n return (\n \n {this.props.errorMessage &&\n {this.props.errorMessage}}\n {this.props.allAthletes && this.props.allEfforts ?\n this.renderNoEffortListTable(this.props.allAthletes, this.props.allEfforts) :\n NoEffortList.renderLoadingIndicator()}\n \n );\n }\n\n private renderNoEffortListTable(athletes: ChallengeDetailsStore.Athlete[], efforts: ChallengeDetailsStore.Effort[]) {\n const showCategory = !(this.props.selectedCategory.maximumAge && this.props.selectedCategory.gender);\n const athletesWithEffort = new Set(efforts.map(e => e.athleteId));\n const athletesWithNoEfforts = athletes.filter(a => !athletesWithEffort.has(a.id));\n if (athletesWithNoEfforts.length > 0) {\n return (\n \n

Athletes With No Times

\n \n \n \n \n {showCategory && }\n \n \n \n {athletesWithNoEfforts.map((athlete: ChallengeDetailsStore.Athlete) =>\n \n \n {showCategory && }\n \n )}\n \n
AthleteCategory
{athlete.displayName}{this.props.login?.loggedInUser?.user_data.is_admin && (` (${athlete.id})`)}{this.getCategory(athlete.age, athlete.gender)}
\n

\n Note: If you recently uploaded a ride it make take 30 minutes to an hour for your segment times to\n appear here. If it takes longer please contact support.\n

\n
\n );\n }\n }\n\n private getCategory(athleteAge: number, athleteGender: string): string {\n if (this.props.ageGroups) {\n let gender = 'Other';\n switch (athleteGender) {\n case 'm':\n case 'M':\n gender = 'Men';\n break;\n case 'f':\n case 'F':\n gender = 'Women';\n break;\n }\n\n const ageGroup = this.props.ageGroups.filter(a => a.maximumAge >= athleteAge)[0];\n if (ageGroup) {\n return `${gender}, ${ageGroup.description}`;\n } else {\n return gender;\n }\n } else {\n return 'Unknown';\n }\n }\n\n private static renderLoadingIndicator() {\n return (\n
Loading? ...
\n )\n }\n}\n\nexport default connect(\n (state: ApplicationState) => ({...state.challengeDetails, login: state.login})\n)(NoEffortList);\n","import * as React from \"react\";\nimport {connect, Matching} from \"react-redux\";\nimport {UploadEffortGpxState} from \"../store/UploadEffortGpx\";\nimport * as ChallengeDetailStore from \"../store/ChallengeDetails\";\nimport * as UploadEffortGpxStore from \"../store/UploadEffortGpx\";\nimport {LoginState} from \"../store/Login\";\nimport {ApplicationState} from \"../store\";\nimport {ChangeEvent} from \"react\";\n\ntype UploadEffortProps =\n UploadEffortGpxStore.UploadEffortGpxState &\n ChallengeDetailStore.ChallengeDetailsState &\n { login?: LoginState } &\n {\n onAthleteIdChanged: (event: ChangeEvent) => void,\n onFileSelected: (event: ChangeEvent) => void,\n uploadFile: () => void,\n cancelUpload: () => void\n };\n\nclass UploadEffortGpx extends React.PureComponent, UploadEffortGpxState> {\n constructor(props: UploadEffortProps) {\n super(props);\n\n this.state = {};\n }\n\n public render() {\n let fileInputRow;\n\n if (this.props.uploaded) {\n fileInputRow = (\n
\n GPX data successfully uploaded.\n
\n );\n } else if (this.props.uploading) {\n fileInputRow = (\n
\n Uploading File: {this.props.selectedFile?.name || \"unknown\"}\n
\n );\n } else if (this.props.errorMessage) {\n fileInputRow = (\n
\n An error occurred: {this.props.errorMessage}\n
\n );\n } else if (this.props.selectedFile) {\n fileInputRow = (\n
\n File selected: {this.props.selectedFile?.name}\n \n \n\n
\n );\n } else {\n fileInputRow = (\n
\n this.props.onFileSelected(e)}/>\n
\n );\n }\n\n return (\n
\n

\n Upload Effort GPX Data\n

\n
\n \n
\n {fileInputRow}\n
\n );\n }\n}\n\nexport default connect(\n (state: ApplicationState) => ({...state.uploadEffortGpx, ...state.challengeDetails, login: state.login}),\n UploadEffortGpxStore.actionCreators\n)(UploadEffortGpx);\n","import * as React from 'react';\nimport {connect, Matching} from 'react-redux';\nimport {RouteComponentProps} from \"react-router\";\nimport {Link} from \"react-router-dom\";\nimport moment from \"moment\";\nimport {ApplicationState} from \"../store\";\nimport {Challenge} from \"../store/ChallengeList\";\nimport * as ChallengeDetailStore from \"../store/ChallengeDetails\"\nimport * as ChallengeListStore from \"../store/ChallengeList\"\nimport JoinButton from \"./JoinButton\";\nimport EffortList from \"./EffortList\";\nimport UploadChallengeGpx from \"./UploadChallengeGpx\";\nimport CategorySelector from \"./CategorySelector\";\nimport {LoginState} from \"../store/Login\";\nimport {Category} from \"../store/ChallengeDetails\";\nimport NoEffortList from \"./NoEffortList\";\nimport UploadEffortGpx from \"./UploadEffortGpx\";\n\ntype ChallengeDetailsProps =\n ChallengeDetailStore.ChallengeDetailsState &\n ChallengeListStore.ChallengeListState &\n { login?: LoginState } &\n {\n onSelectedChallengeChanged: (selectedChallenge: string) => void,\n selectedCategoryChanged: (selectedCategory: Category) => ChallengeDetailStore.SelectedCategoryChanged\n } &\n RouteComponentProps<{ challengeName: string }>;\n\ntype ChallengeDetailsState = { bestEffort?: number }\n\nclass ChallengeDetails extends React.PureComponent, ChallengeDetailsState> {\n constructor(props: ChallengeDetailsProps) {\n super(props);\n\n this.state = {};\n }\n\n public componentDidMount() {\n this.props.onSelectedChallengeChanged(this.props.match.params.challengeName);\n }\n\n public componentDidUpdate() {\n this.props.onSelectedChallengeChanged(this.props.match.params.challengeName);\n\n if (this.props.allEfforts && this.props.login && this.props.login.loggedInUser) {\n const loggedInUser = this.props.login.loggedInUser;\n this.setState({\n bestEffort: this.props.allEfforts.filter(e => e.athleteId === Number(loggedInUser.sub))[0]?.id\n })\n }\n }\n\n public render() {\n return (\n \n {this.props.requestError &&\n {this.props.requestError}}\n {this.props.currentChallenge ?\n this.renderChallengeDetails() :\n (this.props.challenges ? ChallengeDetails.renderNotFound() : ChallengeDetails.renderLoadingIndicator())}\n \n );\n }\n\n private renderChallengeDetails() {\n return this.props.currentChallenge && (\n
\n
\n

{this.props.currentChallenge.displayName}

\n {(this.props.isAthleteRegistered === false) && }\n {this.state.bestEffort ?\n \n Your Effort\n :\n (this.props.isAthleteRegistered === true && You have joined. Check back later for your efforts.)}\n
\n

{this.props.selectedCategory.description}

\n
\n \n {/*
*/}\n {/* */}\n {/*
*/}\n
\n
\n \n
\n {this.props.login?.loggedInUser?.user_data.is_admin && }\n \n
\n );\n }\n\n private static renderLoadingIndicator() {\n return (\n
Loading ...
\n )\n }\n\n private static renderNotFound() {\n\n return (\n
\n The Challenge you are looking for was not found.\n
\n )\n }\n\n private static getSelectedChallenge(challenges: Challenge[], challengeName: string): Challenge | undefined {\n return challenges.filter(c => c.name === challengeName)[0];\n }\n}\n\nexport default connect(\n (state: ApplicationState) => ({...state.challengeList, ...state.challengeDetails, login: state.login}),\n ChallengeDetailStore.actionCreators\n)(ChallengeDetails);\n","import React from 'react';\nimport {Route} from 'react-router';\nimport Layout from './components/Layout';\nimport Home from './components/Home';\nimport ChallengeDetails from \"./components/ChallengeDetails\";\n\nimport './site.scss'\n\nexport default () => (\n \n \n \n \n);\n","// In production, we register a service worker to serve assets from local cache.\n\n// This lets the app load faster on subsequent visits in production, and gives\n// it offline capabilities. However, it also means that developers (and users)\n// will only see deployed updates on the \"N+1\" visit to a page, since previously\n// cached resources are updated in the background.\n\n// To learn more about the benefits of this model, read https://goo.gl/KwvDNy.\n// This link also includes instructions on opting out of this behavior.\n\nconst isLocalhost = Boolean(\n window.location.hostname === 'localhost' ||\n // [::1] is the IPv6 localhost address.\n window.location.hostname === '[::1]' ||\n // 127.0.0.1/8 is considered localhost for IPv4.\n window.location.hostname.match(\n /^127(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/\n )\n);\n\nexport default function register() {\n if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {\n // The URL constructor is available in all browsers that support SW.\n const url = process.env.PUBLIC_URL as string;\n const publicUrl = new URL(url, window.location.toString());\n if (publicUrl.origin !== window.location.origin) {\n // Our service worker won't work if PUBLIC_URL is on a different origin\n // from what our page is served on. This might happen if a CDN is used to\n // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374\n return;\n }\n\n window.addEventListener('load', () => {\n const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;\n\n if (isLocalhost) {\n // This is running on localhost. Lets check if a service worker still exists or not.\n checkValidServiceWorker(swUrl);\n } else {\n // Is not local host. Just register service worker\n registerValidSW(swUrl);\n }\n });\n }\n}\n\nfunction registerValidSW(swUrl: string) {\n navigator.serviceWorker\n .register(swUrl)\n .then(registration => {\n registration.onupdatefound = () => {\n const installingWorker = registration.installing as ServiceWorker;\n installingWorker.onstatechange = () => {\n if (installingWorker.state === 'installed') {\n if (navigator.serviceWorker.controller) {\n // At this point, the old content will have been purged and\n // the fresh content will have been added to the cache.\n // It's the perfect time to display a \"New content is\n // available; please refresh.\" message in your web app.\n console.log('New content is available; please refresh.');\n } else {\n // At this point, everything has been precached.\n // It's the perfect time to display a\n // \"Content is cached for offline use.\" message.\n console.log('Content is cached for offline use.');\n }\n }\n };\n };\n })\n .catch(error => {\n console.error('Error during service worker registration:', error);\n });\n}\n\nfunction checkValidServiceWorker(swUrl: string) {\n // Check if the service worker can be found. If it can't reload the page.\n fetch(swUrl)\n .then(response => {\n // Ensure service worker exists, and that we really are getting a JS file.\n const contentType = response.headers.get('content-type');\n if (response.status === 404 || (contentType && contentType.indexOf('javascript') === -1)) {\n // No service worker found. Probably a different app. Reload the page.\n navigator.serviceWorker.ready.then(registration => {\n registration.unregister().then(() => {\n window.location.reload();\n });\n });\n } else {\n // Service worker found. Proceed as normal.\n registerValidSW(swUrl);\n }\n })\n .catch(() => {\n console.log('No internet connection found. App is running in offline mode.');\n });\n}\n\nexport function unregister() {\n if ('serviceWorker' in navigator) {\n navigator.serviceWorker.ready.then(registration => {\n registration.unregister();\n });\n }\n}\n","import * as React from 'react';\nimport * as ReactDOM from 'react-dom';\nimport { Provider } from 'react-redux';\nimport { ConnectedRouter } from 'connected-react-router';\nimport { createBrowserHistory } from 'history';\nimport configureStore from './store/configureStore';\nimport App from './App';\nimport registerServiceWorker from './registerServiceWorker';\nimport * as RestHelper from './RestHelper';\n\n// Create browser history to use in the Redux store\nconst baseUrl = document.getElementsByTagName('base')[0].getAttribute('href') as string;\nconst history = createBrowserHistory({ basename: baseUrl });\n\n// Check user login state\nlet loggedInUser = RestHelper.getLoggedInUser();\n\nfetch('/config/env.json')\n .then(resp => {\n if (resp.status === 200) {\n const contentType = resp.headers.get('Content-Type');\n if (contentType && (contentType.startsWith('application/json') || contentType.startsWith('text/json'))) {\n return resp.json();\n } else {\n console.warn(`Unexpected content type for /config/env.json: ${contentType}`);\n }\n } else {\n console.warn(`Unexpected status code for /config/env.json: ${resp.status}`);\n }\n\n return {};\n })\n .catch(err => {\n console.warn('Error fetching config json: ' + (err.stack || err.message));\n return {};\n })\n .then((config: any) => {\n // Get the application-wide store instance, prepopulating with state from the server where available.\n const initialState = {\n login: { loggedInUser },\n config: {\n siteTitle: config.siteTitle ?? process.env.REACT_APP_SITE_TITLE ?? 'Strava Segment Challenge',\n siteLogo: config.siteLogo ?? process.env.REACT_APP_SITE_LOGO,\n siteFooter: config.siteFooter ?? process.env.REACT_APP_SITE_FOOTER,\n apiBaseUrl: config.apiBaseUrl ?? process.env.REACT_APP_API_BASE_URL ?? ''\n }\n };\n\n document.title = initialState.config.siteTitle;\n\n const store = configureStore(history, initialState);\n\n ReactDOM.render(\n \n \n \n \n ,\n document.getElementById('root')\n );\n\n registerServiceWorker();\n });\n","import {applyMiddleware, combineReducers, compose, createStore} from 'redux';\nimport thunk from 'redux-thunk';\nimport {connectRouter, routerMiddleware} from 'connected-react-router';\nimport {History} from 'history';\nimport {reducers, ApplicationState} from \"./index\";\n\nexport default function configureStore(history: History, initialState?: ApplicationState) {\n const middleware = [\n thunk,\n routerMiddleware(history)\n ];\n\n const rootReducer = combineReducers({\n ...reducers,\n router: connectRouter(history)\n });\n\n const enhancers = [];\n const windowIfDefined = typeof window === 'undefined' ? null : window as any;\n if (windowIfDefined && windowIfDefined.__REDUX_DEVTOOLS_EXTENSION__) {\n enhancers.push(windowIfDefined.__REDUX_DEVTOOLS_EXTENSION__());\n }\n\n return createStore(\n rootReducer,\n initialState,\n compose(applyMiddleware(...middleware), ...enhancers)\n );\n}\n"],"sourceRoot":""}