github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/web/src/StarredResourcesContext.tsx (about)

     1  import React, {
     2    PropsWithChildren,
     3    useContext,
     4    useEffect,
     5    useState,
     6  } from "react"
     7  import { AnalyticsAction, incr } from "./analytics"
     8  import { usePersistentState } from "./BrowserStorage"
     9  
    10  export type StarredResourcesContext = {
    11    starredResources: string[]
    12    starResource: (name: string) => void
    13    unstarResource: (name: string) => void
    14    toggleStarResource: (name: string) => void
    15  }
    16  
    17  const starredResourceContext = React.createContext<StarredResourcesContext>({
    18    starredResources: [],
    19    starResource: (s) => {},
    20    unstarResource: (s) => {},
    21    toggleStarResource: (s) => {},
    22  })
    23  
    24  export function useStarredResources(): StarredResourcesContext {
    25    return useContext(starredResourceContext)
    26  }
    27  
    28  export function StarredResourceMemoryProvider(
    29    props: PropsWithChildren<{ initialValueForTesting?: string[] }>
    30  ) {
    31    const [starredResources, setStarredResources] = useState<Array<string>>(
    32      props.initialValueForTesting || []
    33    )
    34  
    35    function starResource(name: string) {
    36      setStarredResources((prevState) => {
    37        return prevState.includes(name) ? prevState : [...prevState, name]
    38      })
    39    }
    40  
    41    function unstarResource(name: string) {
    42      setStarredResources((prevState) => {
    43        return prevState.filter((s) => s !== name)
    44      })
    45    }
    46  
    47    function toggleStarResource(name: string) {
    48      if (starredResources.includes(name)) {
    49        unstarResource(name)
    50      } else {
    51        starResource(name)
    52      }
    53    }
    54  
    55    return (
    56      <starredResourceContext.Provider
    57        value={{
    58          starredResources: starredResources,
    59          starResource: starResource,
    60          unstarResource: unstarResource,
    61          toggleStarResource: toggleStarResource,
    62        }}
    63      >
    64        {props.children}
    65      </starredResourceContext.Provider>
    66    )
    67  }
    68  
    69  export function StarredResourcesContextProvider(
    70    props: PropsWithChildren<{ initialValueForTesting?: string[] }>
    71  ) {
    72    // we renamed pins to stars but kept the local storage name "pinned-resources"
    73    // so that user's pinned resources show up as starred
    74    let [starredResources, setStarredResources] = usePersistentState<string[]>(
    75      "pinned-resources",
    76      props.initialValueForTesting ?? []
    77    )
    78  
    79    useEffect(() => {
    80      incr("ui.web.star", {
    81        starCount: starredResources.length.toString(),
    82        action: AnalyticsAction.Load,
    83      })
    84      // empty deps because we only want to report the loaded star count once per app load
    85      // eslint-disable-next-line react-hooks/exhaustive-deps
    86    }, [])
    87  
    88    function starResource(name: string) {
    89      setStarredResources((prevState) => {
    90        const ret = prevState.includes(name) ? prevState : [...prevState, name]
    91        incr("ui.web.star", {
    92          starCount: ret.length.toString(),
    93          action: AnalyticsAction.Star,
    94        })
    95        return ret
    96      })
    97    }
    98  
    99    function unstarResource(name: string) {
   100      setStarredResources((prevState) => {
   101        const ret = prevState.filter((n) => n !== name)
   102        incr("ui.web.star", {
   103          starCount: ret.length.toString(),
   104          action: AnalyticsAction.Unstar,
   105        })
   106        return ret
   107      })
   108    }
   109  
   110    function toggleStarResource(name: string) {
   111      if (starredResources.includes(name)) {
   112        unstarResource(name)
   113      } else {
   114        starResource(name)
   115      }
   116    }
   117  
   118    return (
   119      <starredResourceContext.Provider
   120        value={{
   121          starredResources: starredResources,
   122          starResource: starResource,
   123          unstarResource: unstarResource,
   124          toggleStarResource: toggleStarResource,
   125        }}
   126      >
   127        {props.children}
   128      </starredResourceContext.Provider>
   129    )
   130  }