2021-02-06 20:06:49 +00:00
|
|
|
import { useEffect, useState } from 'react'
|
2021-02-06 19:15:33 +00:00
|
|
|
import { useDispatch } from 'react-redux'
|
2021-02-06 20:06:49 +00:00
|
|
|
import {
|
|
|
|
Api,
|
|
|
|
CalendarItem,
|
|
|
|
Child,
|
|
|
|
Classmate,
|
|
|
|
MenuItem,
|
|
|
|
NewsItem,
|
|
|
|
Notification,
|
|
|
|
ScheduleItem,
|
|
|
|
User,
|
|
|
|
} from '@skolplattformen/embedded-api'
|
2021-02-06 19:15:33 +00:00
|
|
|
import {
|
|
|
|
ApiCall,
|
|
|
|
EntityHookResult,
|
|
|
|
EntityMap,
|
|
|
|
EntityName,
|
|
|
|
EntityStoreRootState,
|
2021-02-06 20:06:49 +00:00
|
|
|
ExtraActionProps,
|
2021-02-06 19:15:33 +00:00
|
|
|
} from './types'
|
|
|
|
import { useApi } from './context'
|
|
|
|
import { loadAction } from './actions'
|
|
|
|
import store from './store'
|
|
|
|
|
|
|
|
interface StoreSelector<T> {
|
|
|
|
(state: EntityStoreRootState): EntityMap<T>
|
|
|
|
}
|
|
|
|
|
|
|
|
const hook = <T>(
|
|
|
|
entityName: EntityName,
|
|
|
|
key: string,
|
|
|
|
defaultValue: T,
|
|
|
|
selector: StoreSelector<T>,
|
|
|
|
apiCaller: (api: Api) => ApiCall<T>,
|
|
|
|
): EntityHookResult<T> => {
|
2021-02-10 10:02:26 +00:00
|
|
|
const getState = (): EntityStoreRootState => store.getState() as unknown as EntityStoreRootState
|
2021-02-06 19:15:33 +00:00
|
|
|
const select = (storeState: EntityStoreRootState) => {
|
|
|
|
const stateMap = selector(storeState) || {}
|
|
|
|
const state = stateMap[key] || { status: 'pending', data: defaultValue }
|
|
|
|
return state
|
|
|
|
}
|
2021-02-08 16:27:51 +00:00
|
|
|
const {
|
|
|
|
api, isLoggedIn, reporter, storage,
|
|
|
|
} = useApi()
|
2021-02-10 10:02:26 +00:00
|
|
|
const initialState = select(getState())
|
2021-02-06 19:15:33 +00:00
|
|
|
const [state, setState] = useState(initialState)
|
|
|
|
const dispatch = useDispatch()
|
|
|
|
|
|
|
|
const load = (force = false) => {
|
|
|
|
if (isLoggedIn && (force || state.status === 'pending')) {
|
|
|
|
const extra: ExtraActionProps<T> = {
|
|
|
|
key,
|
|
|
|
defaultValue,
|
|
|
|
apiCall: apiCaller(api),
|
2021-02-08 16:27:51 +00:00
|
|
|
retries: 0,
|
2021-02-06 19:15:33 +00:00
|
|
|
}
|
2021-02-07 11:32:21 +00:00
|
|
|
|
|
|
|
// Only use cache when not in fake mode
|
2021-02-06 19:15:33 +00:00
|
|
|
if (!api.isFake) {
|
2021-02-07 11:32:21 +00:00
|
|
|
// Only get from cache first time
|
|
|
|
if (state.status === 'pending') {
|
|
|
|
extra.getFromCache = () => storage.getItem(key)
|
|
|
|
}
|
2021-02-06 19:15:33 +00:00
|
|
|
extra.saveToCache = (value: string) => storage.setItem(key, value)
|
|
|
|
}
|
|
|
|
const action = loadAction<T>(entityName, extra)
|
|
|
|
dispatch(action)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
useEffect(() => { load() }, [isLoggedIn])
|
|
|
|
|
|
|
|
const listener = () => {
|
2021-02-10 10:02:26 +00:00
|
|
|
const newState = select(getState())
|
2021-02-06 20:06:49 +00:00
|
|
|
if (newState.status !== state.status
|
|
|
|
|| newState.data !== state.data
|
|
|
|
|| newState.error !== state.error) {
|
2021-02-06 19:15:33 +00:00
|
|
|
setState(newState)
|
2021-02-08 16:27:51 +00:00
|
|
|
|
|
|
|
if (newState.error) {
|
|
|
|
const description = `Error getting ${entityName} from API`
|
|
|
|
reporter.error(newState.error, description)
|
|
|
|
}
|
2021-02-06 19:15:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
useEffect(() => store.subscribe(listener), [])
|
|
|
|
|
|
|
|
return {
|
|
|
|
...state,
|
2021-02-06 20:06:49 +00:00
|
|
|
reload: () => load(true),
|
2021-02-06 19:15:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export const useChildList = () => hook<Child[]>(
|
|
|
|
'CHILDREN',
|
|
|
|
'children',
|
|
|
|
[],
|
2021-02-06 20:06:49 +00:00
|
|
|
(s) => s.children,
|
2021-02-06 19:15:33 +00:00
|
|
|
(api) => () => api.getChildren(),
|
|
|
|
)
|
|
|
|
|
|
|
|
export const useCalendar = (child: Child) => hook<CalendarItem[]>(
|
|
|
|
'CALENDAR',
|
|
|
|
`calendar_${child.id}`,
|
|
|
|
[],
|
2021-02-06 20:06:49 +00:00
|
|
|
(s) => s.calendar,
|
2021-02-06 19:15:33 +00:00
|
|
|
(api) => () => api.getCalendar(child),
|
|
|
|
)
|
|
|
|
|
|
|
|
export const useClassmates = (child: Child) => hook<Classmate[]>(
|
|
|
|
'CLASSMATES',
|
|
|
|
`classmates_${child.id}`,
|
|
|
|
[],
|
2021-02-06 20:06:49 +00:00
|
|
|
(s) => s.classmates,
|
2021-02-06 19:15:33 +00:00
|
|
|
(api) => () => api.getClassmates(child),
|
|
|
|
)
|
|
|
|
|
|
|
|
export const useMenu = (child: Child) => hook<MenuItem[]>(
|
|
|
|
'MENU',
|
|
|
|
`menu_${child.id}`,
|
|
|
|
[],
|
2021-02-06 20:06:49 +00:00
|
|
|
(s) => s.menu,
|
2021-02-06 19:15:33 +00:00
|
|
|
(api) => () => api.getMenu(child),
|
|
|
|
)
|
|
|
|
|
|
|
|
export const useNews = (child: Child) => hook<NewsItem[]>(
|
|
|
|
'NEWS',
|
|
|
|
`news_${child.id}`,
|
|
|
|
[],
|
2021-02-06 20:06:49 +00:00
|
|
|
(s) => s.news,
|
2021-02-06 19:15:33 +00:00
|
|
|
(api) => () => api.getNews(child),
|
|
|
|
)
|
|
|
|
|
2021-02-10 09:48:46 +00:00
|
|
|
export const useNewsDetails = (child: Child, news: NewsItem) => hook<NewsItem>(
|
|
|
|
'NEWS_DETAILS',
|
|
|
|
`news_details_${news.id}`,
|
|
|
|
news,
|
|
|
|
(s) => s.newsDetails,
|
|
|
|
(api) => () => api.getNewsDetails(child, news),
|
|
|
|
)
|
|
|
|
|
2021-02-06 19:15:33 +00:00
|
|
|
export const useNotifications = (child: Child) => hook<Notification[]>(
|
|
|
|
'NOTIFICATIONS',
|
|
|
|
`notifications_${child.id}`,
|
|
|
|
[],
|
2021-02-06 20:06:49 +00:00
|
|
|
(s) => s.notifications,
|
2021-02-06 19:15:33 +00:00
|
|
|
(api) => () => api.getNotifications(child),
|
|
|
|
)
|
|
|
|
|
|
|
|
export const useSchedule = (child: Child, from: string, to: string) => hook<ScheduleItem[]>(
|
|
|
|
'SCHEDULE',
|
|
|
|
`schedule_${child.id}_${from}_${to}`,
|
|
|
|
[],
|
2021-02-06 20:06:49 +00:00
|
|
|
(s) => s.schedule,
|
2021-02-06 19:15:33 +00:00
|
|
|
(api) => () => api.getSchedule(child, from, to),
|
|
|
|
)
|
|
|
|
|
|
|
|
export const useUser = () => hook<User>(
|
|
|
|
'USER',
|
|
|
|
'user',
|
|
|
|
{},
|
2021-02-06 20:06:49 +00:00
|
|
|
(s) => s.user,
|
2021-02-06 19:15:33 +00:00
|
|
|
(api) => () => api.getUser(),
|
|
|
|
)
|