import { Reducer, useCallback, useReducer } from "react"
import { PostcardContextContents, PostcardSource, PostcardVisibility } from "./base"
/**
* Action of {@link usePostcardStorage} changing the current postcard to a new one.
*/
type UsePostcardStorageActionChange = { type: "change", src: PostcardSource }
/**
* Action of {@link usePostcardStorage} changing the visibility of the current postcard.
*/
type UsePostcardStorageActionDisplay = { type: "display", visibility: PostcardVisibility }
/**
* All possible actions of the reducer of {@link usePostcardStorage}.
*/
type UsePostcardStorageAction = UsePostcardStorageActionChange | UsePostcardStorageActionDisplay
/**
* The state of the reducer of {@link usePostcardStorage}.
*/
type UsePostcardStorageState = {
visibility: PostcardVisibility,
currentSrc: PostcardSource,
previousSrc: PostcardSource,
}
/**
* Reducer for {@link usePostcardStorage}.
*/
function reducerUsePostcardStorage(prev: UsePostcardStorageState, action: UsePostcardStorageAction): UsePostcardStorageState {
switch (action.type) {
case "change":
if (action.src !== prev.currentSrc) {
return { ...prev, previousSrc: prev.currentSrc, currentSrc: action.src }
}
else {
return prev
}
case "display":
return { ...prev, visibility: action.visibility }
}
}
/**
* Convert a {@link PostcardSource} to a string suitable for use in `` tags.
*/
function getProperSrc(obj: PostcardSource): string {
if (typeof obj === "string") {
return obj
}
else {
return obj.src
}
}
/**
* Hook holding as state the {@link PostcardContextContents}.
*/
export function usePostcardStorage(defaultPostcard: PostcardSource): PostcardContextContents {
const [{ previousSrc, currentSrc, visibility }, dispatch] = useReducer>(
reducerUsePostcardStorage,
{
visibility: PostcardVisibility.BACKGROUND,
previousSrc: defaultPostcard,
currentSrc: defaultPostcard
}
)
const changePostcard = useCallback(
(src: PostcardSource) => {
dispatch({ type: "change", src })
},
[dispatch]
)
const resetPostcard = useCallback(
() => {
changePostcard(defaultPostcard)
},
[changePostcard, defaultPostcard]
)
const changeVisibility = useCallback(
(visibility: PostcardVisibility) => {
dispatch({ type: "display", visibility })
},
[dispatch]
)
return {
previousSrc: getProperSrc(previousSrc),
currentSrc: getProperSrc(currentSrc),
changePostcard,
resetPostcard,
changeVisibility,
visibility,
};
}