{"version":3,"sources":["../../src/components/LoadingAndErrorComponent.tsx","../../src/hooks/useLanguage.tsx","../../src/hooks/useLocalStorage.tsx","../../src/hooks/useTranslation.ts","../../src/components/icons/Helpwave.tsx","../../src/components/LoadingAnimation.tsx","../../src/components/ErrorComponent.tsx"],"sourcesContent":["import type { PropsWithChildren } from 'react'\nimport { useState } from 'react'\nimport type { LoadingAnimationProps } from './LoadingAnimation'\nimport type { ErrorComponentProps } from './ErrorComponent'\nimport { LoadingAnimation } from './LoadingAnimation'\nimport { ErrorComponent } from './ErrorComponent'\n\nexport type LoadingAndErrorComponentProps = PropsWithChildren<{\n  isLoading?: boolean,\n  hasError?: boolean,\n  loadingProps?: LoadingAnimationProps,\n  errorProps?: ErrorComponentProps,\n  /**\n   * in milliseconds\n   */\n  minimumLoadingDuration?: number,\n}>\n\n/**\n * A Component that shows the Error and Loading animation, when appropriate and the children otherwise\n */\nexport const LoadingAndErrorComponent = ({\n  children,\n  isLoading = false,\n  hasError = false,\n  errorProps,\n  loadingProps,\n  minimumLoadingDuration\n}: LoadingAndErrorComponentProps) => {\n  const [isInMinimumLoading, setIsInMinimumLoading] = useState(false)\n  const [hasUsedMinimumLoading, setHasUsedMinimumLoading] = useState(false)\n  if (minimumLoadingDuration && !isInMinimumLoading && !hasUsedMinimumLoading) {\n    setIsInMinimumLoading(true)\n    setTimeout(() => {\n      setIsInMinimumLoading(false)\n      setHasUsedMinimumLoading(true)\n    }, minimumLoadingDuration)\n  }\n\n  if (isLoading || (minimumLoadingDuration && isInMinimumLoading)) {\n    return <LoadingAnimation {...loadingProps}/>\n  }\n  if (hasError) {\n    return <ErrorComponent {...errorProps}/>\n  }\n  return children\n}\n","import type { Dispatch, PropsWithChildren, SetStateAction } from 'react'\nimport { createContext, useContext, useEffect, useState } from 'react'\nimport { useLocalStorage } from './useLocalStorage'\n\nexport const languages = ['en', 'de'] as const\nexport type Languages = typeof languages[number]\nexport const languagesLocalNames: Record<Languages, string> = {\n  en: 'English',\n  de: 'Deutsch',\n}\n\nexport const DEFAULT_LANGUAGE = 'en'\n\nexport type LanguageContextValue = {\n  language: Languages,\n  setLanguage: Dispatch<SetStateAction<Languages>>,\n}\n\nexport const LanguageContext = createContext<LanguageContextValue>({ language: DEFAULT_LANGUAGE, setLanguage: (v) => v })\n\nexport const useLanguage = () => useContext(LanguageContext)\n\nexport const useLocale = (overWriteLanguage?: Languages) => {\n  const { language } = useLanguage()\n  const mapping: Record<Languages, string> = {\n    en: 'en-US',\n    de: 'de-DE'\n  }\n  return mapping[overWriteLanguage ?? language]\n}\n\ntype ProvideLanguageProps = {\n  initialLanguage?: Languages,\n}\n\nexport const ProvideLanguage = ({ initialLanguage, children }: PropsWithChildren<ProvideLanguageProps>) => {\n  const [language, setLanguage] = useState<Languages>(initialLanguage ?? DEFAULT_LANGUAGE)\n  const [storedLanguage, setStoredLanguage] = useLocalStorage<Languages>('language', initialLanguage ?? DEFAULT_LANGUAGE)\n\n  useEffect(() => {\n    if(language !== initialLanguage && initialLanguage){\n      console.warn('LanguageProvider initial state changed: Prefer using useLanguages\\'s setLanguage instead')\n      setLanguage(initialLanguage)\n    }\n  }, [initialLanguage]) // eslint-disable-line react-hooks/exhaustive-deps\n\n  useEffect(() => {\n    // TODO set locale of html tag here as well\n    setStoredLanguage(language)\n  }, [language, setStoredLanguage])\n\n  useEffect(() => {\n    if (storedLanguage !== null) {\n      setLanguage(storedLanguage)\n      return\n    }\n\n    const languagesToTestAgainst = Object.values(languages)\n\n    const matchingBrowserLanguages = window.navigator.languages\n      .map(language => languagesToTestAgainst.find((test) => language === test || language.split('-')[0] === test))\n      .filter(entry => entry !== undefined)\n\n    if (matchingBrowserLanguages.length === 0) return\n\n    const firstMatch = matchingBrowserLanguages[0] as Languages\n    setLanguage(firstMatch)\n  }, []) // eslint-disable-line react-hooks/exhaustive-deps\n\n  return (\n    <LanguageContext.Provider value={{\n      language,\n      setLanguage\n    }}>\n      {children}\n    </LanguageContext.Provider>\n  )\n}\n","import type { Dispatch, SetStateAction } from 'react'\nimport { useCallback, useEffect, useState } from 'react'\nimport { LocalStorageService } from '../util/storage'\n\ntype SetValue<T> = Dispatch<SetStateAction<T>>\nexport const useLocalStorage = <T, >(key: string, initValue: T): [T, SetValue<T>] => {\n  const get = useCallback((): T => {\n    if (typeof window === 'undefined') {\n      return initValue\n    }\n    const storageService = new LocalStorageService()\n    const value = storageService.get<T>(key)\n    return value || initValue\n  }, [initValue, key])\n\n  const [storedValue, setStoredValue] = useState<T>(get)\n\n  const setValue: SetValue<T> = useCallback(value => {\n    const newValue = value instanceof Function ? value(storedValue) : value\n    const storageService = new LocalStorageService()\n    storageService.set(key, value)\n\n    setStoredValue(newValue)\n  }, [storedValue, setStoredValue, key])\n\n  useEffect(() => {\n    setStoredValue(get())\n  }, []) // eslint-disable-line react-hooks/exhaustive-deps\n\n  return [storedValue, setValue]\n}","import type { Languages } from './useLanguage'\nimport { useLanguage } from './useLanguage'\n\nexport type Translation<T> = Record<Languages, T>\n\ntype OverwriteTranslationType<Translation extends Record<string, unknown>> = {\n  language?: Languages,\n  translation?: Partial<Record<Languages, Partial<Translation>>>,\n}\n\n/**\n * Adds the `language` prop to the component props.\n *\n * @param Translation the type of the translation object\n *\n * @param Props the type of the component props, defaults to `Record<string, never>`,\n *              if you don't expect any other props other than `language` and get an\n *              error when using your component (because it uses `forwardRef` etc.)\n *              you can try out `Record<string, unknown>`, this might resolve your\n *              problem as `SomeType & never` is still `never` but `SomeType & unknown`\n *              is `SomeType` which means that adding back props (like `ref` etc.)\n *              works properly\n */\nexport type PropsForTranslation<\n  Translation extends Record<string, unknown>,\n  Props = Record<string, never>\n> = Props & {\n  overwriteTranslation?: OverwriteTranslationType<Translation>,\n};\n\nexport const useTranslation = <Translation extends Record<string, unknown>>(\n  defaults: Record<Languages, Translation>,\n  translationOverwrite: OverwriteTranslationType<Translation> = {}\n) : Translation => {\n  const { language: languageProp, translation: overwrite } = translationOverwrite\n  const { language: inferredLanguage } = useLanguage()\n  const usedLanguage = languageProp ?? inferredLanguage\n  let defaultValues: Translation = defaults[usedLanguage]\n  if (overwrite && overwrite[usedLanguage]) {\n    defaultValues = { ...defaultValues, ...overwrite[usedLanguage] }\n  }\n  return defaultValues\n}\n","import type { SVGProps } from 'react'\nimport { clsx } from 'clsx'\n\nexport type HelpwaveProps = SVGProps<SVGSVGElement> & {\n  color?: string,\n  animate?: 'none' | 'loading' | 'pulse' | 'bounce',\n  size?: number,\n}\n\n/**\n * The helpwave loading spinner based on the svg logo.\n */\nexport const Helpwave = ({\n  color = 'currentColor',\n  animate = 'none',\n  size = 64,\n  ...props\n}: HelpwaveProps) => {\n  const isLoadingAnimation = animate === 'loading'\n  let svgAnimationKey = ''\n\n  if (animate === 'pulse') {\n    svgAnimationKey = 'animate-pulse'\n  } else if (animate === 'bounce') {\n    svgAnimationKey = 'animate-bounce'\n  }\n\n  if (size < 0) {\n    console.error('size cannot be less than 0')\n    size = 64\n  }\n\n  return (\n    <svg\n      width={size}\n      height={size}\n      viewBox=\"0 0 888 888\"\n      fill=\"none\"\n      strokeLinecap=\"round\"\n      strokeWidth={48}\n      {...props}\n    >\n      <g className={clsx(svgAnimationKey)}>\n        <path className={clsx({ 'animate-wave-big-left-up': isLoadingAnimation })} d=\"M144 543.235C144 423.259 232.164 326 340.92 326\" stroke={color} strokeDasharray=\"1000\" />\n        <path className={clsx({ 'animate-wave-big-right-down': isLoadingAnimation })} d=\"M537.84 544.104C429.084 544.104 340.92 446.844 340.92 326.869\" stroke={color} strokeDasharray=\"1000\" />\n        <path className={clsx({ 'animate-wave-small-left-up': isLoadingAnimation })} d=\"M462.223 518.035C462.223 432.133 525.348 362.495 603.217 362.495\" stroke={color} strokeDasharray=\"1000\" />\n        <path className={clsx({ 'animate-wave-small-right-down': isLoadingAnimation })} d=\"M745.001 519.773C666.696 519.773 603.218 450.136 603.218 364.233\" stroke={color} strokeDasharray=\"1000\" />\n      </g>\n    </svg>\n  )\n}\n","import type { Languages } from '../hooks/useLanguage'\nimport type { PropsForTranslation } from '../hooks/useTranslation'\nimport { useTranslation } from '../hooks/useTranslation'\nimport { Helpwave } from './icons/Helpwave'\nimport clsx from 'clsx'\n\ntype LoadingAnimationTranslation = {\n  loading: string,\n}\n\nconst defaultLoadingAnimationTranslation: Record<Languages, LoadingAnimationTranslation> = {\n  en: {\n    loading: 'Loading data'\n  },\n  de: {\n    loading: 'Lade Daten'\n  }\n}\n\nexport type LoadingAnimationProps = {\n  loadingText?: string,\n  classname?: string,\n}\n\n/**\n * A Component to show when loading data\n */\nexport const LoadingAnimation = ({\n  overwriteTranslation,\n  loadingText,\n  classname\n}: PropsForTranslation<LoadingAnimationTranslation, LoadingAnimationProps>) => {\n  const translation = useTranslation(defaultLoadingAnimationTranslation, overwriteTranslation)\n  return (\n    <div className={clsx('col items-center justify-center w-full h-24', classname)}>\n      <Helpwave animate=\"loading\" />\n      {loadingText ?? `${translation.loading}...`}\n    </div>\n  )\n}\n","import { AlertOctagon } from 'lucide-react'\nimport type { Languages } from '../hooks/useLanguage'\nimport type { PropsForTranslation } from '../hooks/useTranslation'\nimport { useTranslation } from '../hooks/useTranslation'\nimport clsx from 'clsx'\n\ntype ErrorComponentTranslation = {\n  errorOccurred: string,\n}\n\nconst defaultErrorComponentTranslation: Record<Languages, ErrorComponentTranslation> = {\n  en: {\n    errorOccurred: 'An error occurred'\n  },\n  de: {\n    errorOccurred: 'Ein Fehler ist aufgetreten'\n  }\n}\n\nexport type ErrorComponentProps = {\n  errorText?: string,\n  classname?: string,\n}\n\n/**\n * The Component to show when an error occurred\n */\nexport const ErrorComponent = ({\n  overwriteTranslation,\n  errorText,\n  classname\n}: PropsForTranslation<ErrorComponentTranslation, ErrorComponentProps>) => {\n  const translation = useTranslation(defaultErrorComponentTranslation, overwriteTranslation)\n  return (\n    <div className={clsx('col items-center justify-center gap-y-4 w-full h-24', classname)}>\n      <AlertOctagon size={64} className=\"text-warning\"/>\n      {errorText ?? `${translation.errorOccurred} :(`}\n    </div>\n  )\n}\n"],"mappings":"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","names":["useState","useEffect","useState","jsx","clsx","jsx","jsxs","clsx","jsx","jsxs","jsx","useState"]}