Skip to content

Commit

Permalink
refactor(front): rename Result.. -> Global.., split out autorefresh h…
Browse files Browse the repository at this point in the history
…ook (#349)

rename ResultStore -> GlobalStore

remove current autorefresh

add recursive timout hook

remove stuff from recursivetimeout

rename ResultContext -> GlobalContext

Signed-off-by: Elizabeth Kelen <[email protected]>
  • Loading branch information
ekelen authored Jun 16, 2020
1 parent 3308fdb commit 50deb7a
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 48 deletions.
6 changes: 3 additions & 3 deletions web/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
} from 'react-router-dom'
import 'tabler-react/dist/Tabler.css'
import './assets/main.scss'
import { ResultStore } from './store/ResultStore'
import { GlobalStore } from './store/GlobalStore'
import { ThemeContext, ThemeStore } from './store/ThemeStore'
import Error404 from './ui/pages/Error404/Error404'
import Home from './ui/pages/Home/Home'
Expand Down Expand Up @@ -36,9 +36,9 @@ const AppRouter = () => {

const App = () => (
<ThemeStore>
<ResultStore>
<GlobalStore>
<AppRouter />
</ResultStore>
</GlobalStore>
</ThemeStore>
)

Expand Down
33 changes: 33 additions & 0 deletions web/src/hooks/useRecursiveTimeout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { useEffect, useRef } from 'react'

/**
* Source: https://www.aaron-powell.com/posts/2019-09-23-recursive-settimeout-with-react-hooks/
*/
export const useRecursiveTimeout = (
callback = () => { },
delay = 0,
) => {
const savedCallback = useRef(callback)

// Remember the latest callback.
useEffect(() => {
savedCallback.current = callback
}, [callback])

// Set up the timeout loop.
// eslint-disable-next-line consistent-return
useEffect(() => {
let timerId
function tick() {
savedCallback.current()

if (delay !== null) {
timerId = setTimeout(tick, delay)
}
}
if (delay !== null) {
timerId = setTimeout(tick, delay)
return () => timerId && clearTimeout(timerId)
}
}, [delay])
}
12 changes: 8 additions & 4 deletions web/src/store/ResultStore.js → web/src/store/GlobalStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
PROJECT_BUILD_DRIVER,
} from '../constants'

export const ResultContext = React.createContext()
export const GlobalContext = React.createContext()

export const INITIAL_STATE = {
apiKey: retrieveAuthCookie() || null,
Expand Down Expand Up @@ -51,22 +51,26 @@ function reducer(state, action) {
}
}

export const ResultStore = ({ children }) => {
export const GlobalStore = ({ children }) => {
const [state, dispatch] = useReducer(reducer, INITIAL_STATE)

// custom actions can go here; for now we just have one
// 🚧 not cool, we need to split this so we don't get redundant re-renders
// or have to do a slow deep equality check to prevent it
const updateState = (payload) => {
dispatch({ type: actions.UPDATE_STATE, payload: cloneDeep(payload) })
}


return (
<ResultContext.Provider
<GlobalContext.Provider
value={{
state,
updateState,
dispatch,
}}
>
{children}
</ResultContext.Provider>
</GlobalContext.Provider>
)
}
4 changes: 2 additions & 2 deletions web/src/ui/components/Build/BuildContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { get } from 'lodash'
import React, { useContext, useState } from 'react'
import { ARTIFACT_KIND_NAMES, BRANCH, BUILD_STATE } from '../../../constants'
import { ResultContext } from '../../../store/ResultStore'
import { GlobalContext } from '../../../store/GlobalStore'
import { ThemeContext } from '../../../store/ThemeStore'
import { getIsArray, getIsArrayWithN, getStrEquNormalized } from '../../../util/getters'
import { getArtifactKindIcon } from '../../styleTools/brandIcons'
Expand Down Expand Up @@ -51,7 +51,7 @@ const AnyRunningBuildTags = ({ hasRunningBuilds, allBuildsForMr, theme }) => (ha
const BuildContainer = React.memo(({
build, toCollapse, children, hasRunningBuilds,
}) => {
const { state } = useContext(ResultContext)
const { state } = useContext(GlobalContext)
const [collapsed, toggleCollapsed] = useState(toCollapse)
const [showingAllBuilds, toggleShowingAllBuilds] = useState(false)
const { theme } = useContext(ThemeContext)
Expand Down
4 changes: 2 additions & 2 deletions web/src/ui/components/FilterModal/FilterModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { removeAuthCookie } from '../../../api/cookies'
import {
ARTIFACT_KINDS, BUILD_DRIVERS, BUILD_STATES, PROJECT, PROJECTS,
} from '../../../constants'
import { INITIAL_STATE, ResultContext } from '../../../store/ResultStore'
import { INITIAL_STATE, GlobalContext } from '../../../store/GlobalStore'
import { ThemeContext } from '../../../store/ThemeStore'
import Tag from '../Tag/Tag'
import ThemeToggler from '../ThemeToggler'
Expand Down Expand Up @@ -68,7 +68,7 @@ const BuildStateWidgets = ({ selectedBuildStates, setSelectedBuildStates }) => (

const FilterModal = ({ closeAction }) => {
const { theme, themeStyles } = useContext(ThemeContext)
const { state, updateState } = useContext(ResultContext)
const { state, updateState } = useContext(GlobalContext)
const [selectedDrivers, setSelectedDrivers] = useState([
...state.uiFilters.build_driver,
])
Expand Down
10 changes: 6 additions & 4 deletions web/src/ui/components/Filters/Filters.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import { removeAuthCookie } from '../../../api/cookies'
import {
ARTIFACT_VALUE_KIND, BUILD_DRIVERS, BUILD_DRIVER_TO_NAME, BUILD_STATES, BUILD_STATE_VALUE_TO_NAME, PROJECT, PROJECT_NAME,
} from '../../../constants'
import { ResultContext } from '../../../store/ResultStore.js'
import { GlobalContext } from '../../../store/GlobalStore.js'
import { getIsArrayWithN } from '../../../util/getters.js'
import { getArtifactKindIcon } from '../../styleTools/brandIcons.js'
import OutlineWidget from '../OutlineWidget/OutlineWidget.js'
import styles from './Filters.module.scss'
import IconProjectBertyMessenger from '../../../assets/svg/IconProjectBertyMessenger'

const Filters = React.memo(({ autoRefreshOn, onFilterClick, setAutoRefreshOn }) => {
const Filters = React.memo(({ autoRefreshOn = false, onFilterClick = () => { }, setAutoRefreshOn = () => { } }) => {
const {
state: {
uiFilters: {
Expand All @@ -25,7 +25,7 @@ const Filters = React.memo(({ autoRefreshOn, onFilterClick, setAutoRefreshOn })
projects,
},
}, updateState,
} = useContext(ResultContext)
} = useContext(GlobalContext)

const FilterMessenger = () => (projects.includes(PROJECT.messenger) && (
<OutlineWidget
Expand Down Expand Up @@ -173,6 +173,8 @@ const Filters = React.memo(({ autoRefreshOn, onFilterClick, setAutoRefreshOn })
)
})

Filters.whyDidYouRender = true
Filters.whyDidYouRender = {
logOwnerReasons: true,
}

export default Filters
4 changes: 2 additions & 2 deletions web/src/ui/components/Header/Header.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useContext } from 'react'
import { useHistory, useLocation } from 'react-router-dom'
import YoloLogo from '../../../assets/svg/yolo.svg'
import { INITIAL_STATE, ResultContext } from '../../../store/ResultStore'
import { INITIAL_STATE, GlobalContext } from '../../../store/GlobalStore'
import Filters from '../Filters/Filters'
import styles from './Header.module.scss'

Expand All @@ -10,7 +10,7 @@ const Header = ({
setAutoRefreshOn,
onFilterClick = () => { },
}) => {
const { state, updateState } = useContext(ResultContext)
const { state, updateState } = useContext(GlobalContext)
const history = useHistory()
const location = useLocation()

Expand Down
48 changes: 17 additions & 31 deletions web/src/ui/pages/Home/Home.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { validateError } from '../../../api/apiResponseTransforms'
import {
ARTIFACT_KINDS, BUILD_DRIVERS, BUILD_STATES, DEFAULT_RESULT_REQUEST_LIMIT, PLATFORM_TO_ARTIFACT_KIND, KIND_TO_PLATFORM,
} from '../../../constants'
import { INITIAL_STATE, ResultContext } from '../../../store/ResultStore'
import { INITIAL_STATE, GlobalContext } from '../../../store/GlobalStore'
import { ThemeContext } from '../../../store/ThemeStore'
import { getMobileOperatingSystem } from '../../../util/browser'
import { singleItemToArray } from '../../../util/getters'
Expand All @@ -36,17 +36,26 @@ import Header from '../../components/Header/Header'
import ProtocolDisclaimer from '../../components/ProtocolDisclaimer'
import ShowFiltersButton from '../../components/ShowFiltersButton'
import styles from './Home.module.scss'
import { useRecursiveTimeout } from '../../../hooks/useRecursiveTimeout'

const Home = () => {
const { theme } = useContext(ThemeContext)
const { state, updateState } = useContext(ResultContext)
const { state, updateState } = useContext(GlobalContext)
const [showingFiltersModal, toggleShowFilters] = useState(false)
const [showingDisclaimerModal, toggleShowDisclaimer] = useState(false)
const [needsNewFetch, setNeedsNewFetch] = useState(false)
const [autoRefreshOn, setAutoRefreshOn] = useState(false)
const { search: locationSearch } = useLocation()
const history = useHistory()

useRecursiveTimeout(() => {
if (autoRefreshOn && !showingFiltersModal && !showingDisclaimerModal) {
updateState({
needsRefresh: true,
})
}
}, 10 * 1000)

// 🚧 Hacky - On initial render, set/get query params based on URL bar or state.uiFilters
useEffect(() => {
if (!locationSearch) {
Expand Down Expand Up @@ -183,33 +192,6 @@ const Home = () => {
if (state.needsRefresh === true) triggerNewQuery()
}, [state.needsRefresh])

// 🚧 If autoRefresh is enabled, trigger API call every 10 sec
useEffect(() => {
let timer
if (
!showingDisclaimerModal
&& !showingFiltersModal
&& autoRefreshOn
) {
clearInterval(timer)
timer = setInterval(() => {
updateState({
needsRefresh: true,
})
}, 10000)
} else {
clearInterval(timer)
}
return () => {
clearInterval(timer)
}
}, [
showingDisclaimerModal,
showingFiltersModal,
autoRefreshOn,
updateState,
])

// Show protocol warning modal + agreement on component render
useEffect(() => {
const disclaimerAccepted = Cookies.get('disclaimerAccepted')
Expand All @@ -222,10 +204,15 @@ const Home = () => {
toggleShowDisclaimer(!accepted)
}


return (
<div className={styles.homeContainer}>
<div className={styles.homepageWrapper} style={{ backgroundColor: theme.bg.page }}>
<Header autoRefreshOn={autoRefreshOn} setAutoRefreshOn={setAutoRefreshOn} onFilterClick={toggleShowFilters} />
<Header
autoRefreshOn={autoRefreshOn}
setAutoRefreshOn={setAutoRefreshOn}
onFilterClick={toggleShowFilters}
/>
{state.error && <ErrorDisplay error={state.error} />}
{state.error && state.error.status === 401 && (
<ApiKeyPrompt failedKey={state.apiKey} updateState={updateState} authIsPending={state.authIsPending} />
Expand All @@ -235,7 +222,6 @@ const Home = () => {
)}
<div
className={styles.footer}
// className="footer p-4"
style={{ backgroundColor: theme.bg.block }}
/>
</div>
Expand Down

0 comments on commit 50deb7a

Please sign in to comment.