diff --git a/package.json b/package.json index 5d8fff5e..a483362e 100644 --- a/package.json +++ b/package.json @@ -98,7 +98,7 @@ "npm-run-all": "^4.1.5", "prisma": "5.4.2", "react": "^18.2.0", - "react-basics": "^0.106.0", + "react-basics": "^0.107.0", "react-beautiful-dnd": "^13.1.0", "react-dom": "^18.2.0", "react-error-boundary": "^4.0.4", diff --git a/src/components/common/HamburgerButton.js b/src/components/common/HamburgerButton.tsx similarity index 89% rename from src/components/common/HamburgerButton.js rename to src/components/common/HamburgerButton.tsx index 0eddad0f..380392c8 100644 --- a/src/components/common/HamburgerButton.js +++ b/src/components/common/HamburgerButton.tsx @@ -3,7 +3,7 @@ import { useState } from 'react'; import MobileMenu from './MobileMenu'; import Icons from 'components/icons'; -export function HamburgerButton({ menuItems }) { +export function HamburgerButton({ menuItems }: { menuItems: any[] }) { const [active, setActive] = useState(false); const handleClick = () => setActive(state => !state); diff --git a/src/components/common/HoverTooltip.js b/src/components/common/HoverTooltip.tsx similarity index 82% rename from src/components/common/HoverTooltip.js rename to src/components/common/HoverTooltip.tsx index 614841df..e5e31219 100644 --- a/src/components/common/HoverTooltip.js +++ b/src/components/common/HoverTooltip.tsx @@ -1,8 +1,8 @@ -import { useEffect, useState } from 'react'; +import { ReactNode, useEffect, useState } from 'react'; import { Tooltip } from 'react-basics'; import styles from './HoverTooltip.module.css'; -export function HoverTooltip({ children }) { +export function HoverTooltip({ children }: { children: ReactNode }) { const [position, setPosition] = useState({ x: -1000, y: -1000 }); useEffect(() => { diff --git a/src/components/common/LinkButton.tsx b/src/components/common/LinkButton.tsx index c9366e5c..83d95151 100644 --- a/src/components/common/LinkButton.tsx +++ b/src/components/common/LinkButton.tsx @@ -6,7 +6,7 @@ import { ReactNode } from 'react'; export interface LinkButtonProps { href: string; - className: string; + className?: string; variant?: string; scroll?: boolean; children?: ReactNode; diff --git a/src/components/common/MobileMenu.js b/src/components/common/MobileMenu.tsx similarity index 74% rename from src/components/common/MobileMenu.js rename to src/components/common/MobileMenu.tsx index 83a05dff..251085a4 100644 --- a/src/components/common/MobileMenu.js +++ b/src/components/common/MobileMenu.tsx @@ -4,12 +4,19 @@ import { usePathname } from 'next/navigation'; import Link from 'next/link'; import styles from './MobileMenu.module.css'; -export function MobileMenu({ items = [], onClose }) { +export function MobileMenu({ + items = [], + onClose, +}: { + items: any[]; + className?: string; + onClose: () => void; +}) { const pathname = usePathname(); - const Items = ({ items, className }) => ( + const Items = ({ items, className }: { items: any[]; className?: string }) => (
- {items.map(({ label, url, children }) => { + {items.map(({ label, url, children }: { label: string; url: string; children: any[] }) => { const selected = pathname.startsWith(url); return ( diff --git a/src/components/common/Pager.js b/src/components/common/Pager.tsx similarity index 86% rename from src/components/common/Pager.js rename to src/components/common/Pager.tsx index a21d35d9..2fe7c6db 100644 --- a/src/components/common/Pager.js +++ b/src/components/common/Pager.tsx @@ -3,7 +3,15 @@ import { Button, Icon, Icons } from 'react-basics'; import useMessages from 'components/hooks/useMessages'; import styles from './Pager.module.css'; -export function Pager({ page, pageSize, count, onPageChange, className }) { +export interface PagerProps { + page: number; + pageSize: number; + count: number; + onPageChange: (nextPage: number) => void; + className?: string; +} + +export function Pager({ page, pageSize, count, onPageChange, className }: PagerProps) { const { formatMessage, labels } = useMessages(); const maxPage = pageSize && count ? Math.ceil(count / pageSize) : 0; const lastPage = page === maxPage; @@ -13,7 +21,7 @@ export function Pager({ page, pageSize, count, onPageChange, className }) { return null; } - const handlePageChange = value => { + const handlePageChange = (value: number) => { const nextPage = page + value; if (nextPage > 0 && nextPage <= maxPage) { onPageChange(nextPage); diff --git a/src/components/declarations.d.ts b/src/components/declarations.d.ts index 31e44ff3..81533301 100644 --- a/src/components/declarations.d.ts +++ b/src/components/declarations.d.ts @@ -1,2 +1,3 @@ declare module '*.css'; declare module '*.svg'; +declare module '*.json'; diff --git a/src/components/hooks/useConfig.js b/src/components/hooks/useConfig.ts similarity index 100% rename from src/components/hooks/useConfig.js rename to src/components/hooks/useConfig.ts diff --git a/src/components/hooks/useCountryNames.js b/src/components/hooks/useCountryNames.ts similarity index 87% rename from src/components/hooks/useCountryNames.js rename to src/components/hooks/useCountryNames.ts index 40611865..22f20666 100644 --- a/src/components/hooks/useCountryNames.js +++ b/src/components/hooks/useCountryNames.ts @@ -6,10 +6,10 @@ const countryNames = { 'en-US': enUS, }; -export function useCountryNames(locale) { +export function useCountryNames(locale: string) { const [list, setList] = useState(countryNames[locale] || enUS); - async function loadData(locale) { + async function loadData(locale: string) { const { data } = await httpGet(`${process.env.basePath}/intl/country/${locale}.json`); if (data) { diff --git a/src/components/hooks/useDateRange.js b/src/components/hooks/useDateRange.ts similarity index 91% rename from src/components/hooks/useDateRange.js rename to src/components/hooks/useDateRange.ts index 1e1b0616..6e70a368 100644 --- a/src/components/hooks/useDateRange.js +++ b/src/components/hooks/useDateRange.ts @@ -6,7 +6,7 @@ import websiteStore, { setWebsiteDateRange } from 'store/websites'; import appStore, { setDateRange } from 'store/app'; import useApi from './useApi'; -export function useDateRange(websiteId) { +export function useDateRange(websiteId: string) { const { get } = useApi(); const { locale } = useLocale(); const websiteConfig = websiteStore(state => state[websiteId]?.dateRange); @@ -20,7 +20,7 @@ export function useDateRange(websiteId) { if (typeof value === 'string') { if (value === 'all') { - const result = await get(`/websites/${websiteId}/daterange`); + const result: any = await get(`/websites/${websiteId}/daterange`); const { mindate, maxdate } = result; const startDate = new Date(mindate); diff --git a/src/components/hooks/useDocumentClick.js b/src/components/hooks/useDocumentClick.ts similarity index 77% rename from src/components/hooks/useDocumentClick.js rename to src/components/hooks/useDocumentClick.ts index be3d09be..eefd9366 100644 --- a/src/components/hooks/useDocumentClick.js +++ b/src/components/hooks/useDocumentClick.ts @@ -1,6 +1,6 @@ import { useEffect } from 'react'; -export function useDocumentClick(handler) { +export function useDocumentClick(handler: (event: MouseEvent) => any) { useEffect(() => { document.addEventListener('click', handler); diff --git a/src/components/hooks/useEscapeKey.js b/src/components/hooks/useEscapeKey.js deleted file mode 100644 index 1a17f18f..00000000 --- a/src/components/hooks/useEscapeKey.js +++ /dev/null @@ -1,21 +0,0 @@ -import { useEffect, useCallback } from 'react'; - -export function useEscapeKey(handler) { - const escFunction = useCallback(event => { - if (event.keyCode === 27) { - handler(event); - } - }, []); - - useEffect(() => { - document.addEventListener('keydown', escFunction, false); - - return () => { - document.removeEventListener('keydown', escFunction, false); - }; - }, [escFunction]); - - return null; -} - -export default useEscapeKey; diff --git a/src/components/hooks/useEscapeKey.ts b/src/components/hooks/useEscapeKey.ts new file mode 100644 index 00000000..5c3350e7 --- /dev/null +++ b/src/components/hooks/useEscapeKey.ts @@ -0,0 +1,21 @@ +import { useEffect, useCallback, KeyboardEvent } from 'react'; + +export function useEscapeKey(handler: (event: KeyboardEvent) => void) { + const escFunction = useCallback((event: KeyboardEvent) => { + if (event.key === 'Escape') { + handler(event); + } + }, []); + + useEffect(() => { + document.addEventListener('keydown', escFunction as any, false); + + return () => { + document.removeEventListener('keydown', escFunction as any, false); + }; + }, [escFunction]); + + return null; +} + +export default useEscapeKey; diff --git a/src/components/hooks/useFilters.js b/src/components/hooks/useFilters.ts similarity index 100% rename from src/components/hooks/useFilters.js rename to src/components/hooks/useFilters.ts diff --git a/src/components/hooks/useForceUpdate.js b/src/components/hooks/useForceUpdate.ts similarity index 100% rename from src/components/hooks/useForceUpdate.js rename to src/components/hooks/useForceUpdate.ts diff --git a/src/components/hooks/useFormat.js b/src/components/hooks/useFormat.ts similarity index 81% rename from src/components/hooks/useFormat.js rename to src/components/hooks/useFormat.ts index 0e609c48..c1160162 100644 --- a/src/components/hooks/useFormat.js +++ b/src/components/hooks/useFormat.ts @@ -9,23 +9,23 @@ export function useFormat() { const { locale } = useLocale(); const countryNames = useCountryNames(locale); - const formatBrowser = value => { + const formatBrowser = (value: string) => { return BROWSERS[value] || value; }; - const formatCountry = value => { + const formatCountry = (value: string) => { return countryNames[value] || value; }; - const formatRegion = value => { + const formatRegion = (value: string) => { return regions[value] ? regions[value] : value; }; - const formatDevice = value => { + const formatDevice = (value: string) => { return formatMessage(labels[value] || labels.unknown); }; - const formatValue = (value, type) => { + const formatValue = (value: string, type: string) => { switch (type) { case 'browser': return formatBrowser(value); diff --git a/src/components/hooks/useLanguageNames.js b/src/components/hooks/useLanguageNames.ts similarity index 100% rename from src/components/hooks/useLanguageNames.js rename to src/components/hooks/useLanguageNames.ts diff --git a/src/components/hooks/useLocale.js b/src/components/hooks/useLocale.ts similarity index 100% rename from src/components/hooks/useLocale.js rename to src/components/hooks/useLocale.ts diff --git a/src/components/hooks/useMessages.js b/src/components/hooks/useMessages.ts similarity index 81% rename from src/components/hooks/useMessages.js rename to src/components/hooks/useMessages.ts index e3a6c20b..0801c7d9 100644 --- a/src/components/hooks/useMessages.js +++ b/src/components/hooks/useMessages.ts @@ -4,13 +4,13 @@ import { messages, labels } from 'components/messages'; export function useMessages() { const intl = useIntl(); - const getMessage = id => { + const getMessage = (id: string) => { const message = Object.values(messages).find(value => value.id === id); return message ? formatMessage(message) : id; }; - const formatMessage = (descriptor, values, opts) => { + const formatMessage = (descriptor: any, values?: any, opts?: any) => { return descriptor ? intl.formatMessage(descriptor, values, opts) : null; }; diff --git a/src/components/hooks/useNavigation.js b/src/components/hooks/useNavigation.ts similarity index 100% rename from src/components/hooks/useNavigation.js rename to src/components/hooks/useNavigation.ts diff --git a/src/components/hooks/useReport.js b/src/components/hooks/useReport.ts similarity index 94% rename from src/components/hooks/useReport.js rename to src/components/hooks/useReport.ts index 7c698b4e..1686e222 100644 --- a/src/components/hooks/useReport.js +++ b/src/components/hooks/useReport.ts @@ -18,7 +18,7 @@ export function useReport(reportId, defaultParameters) { }; const loadReport = async id => { - const data = await get(`/reports/${id}`); + const data: any = await get(`/reports/${id}`); const { dateRange } = data?.parameters || {}; const { startDate, endDate } = dateRange || {}; @@ -40,7 +40,7 @@ export function useReport(reportId, defaultParameters) { const data = await post(`/reports/${type}`, { ...parameters, timezone }); setReport( - produce(state => { + produce((state: any) => { state.parameters = parameters; state.data = data; @@ -56,7 +56,7 @@ export function useReport(reportId, defaultParameters) { const updateReport = useCallback( async data => { setReport( - produce(state => { + produce((state: any) => { const { parameters, ...rest } = data; if (parameters) { diff --git a/src/components/hooks/useReports.js b/src/components/hooks/useReports.ts similarity index 100% rename from src/components/hooks/useReports.js rename to src/components/hooks/useReports.ts diff --git a/src/components/hooks/useShareToken.js b/src/components/hooks/useShareToken.ts similarity index 77% rename from src/components/hooks/useShareToken.js rename to src/components/hooks/useShareToken.ts index 5062c73e..088f643e 100644 --- a/src/components/hooks/useShareToken.js +++ b/src/components/hooks/useShareToken.ts @@ -1,9 +1,9 @@ import useStore, { setShareToken } from 'store/app'; import useApi from './useApi'; -const selector = state => state.shareToken; +const selector = (state: { shareToken: string }) => state.shareToken; -export function useShareToken(shareId) { +export function useShareToken(shareId: string) { const shareToken = useStore(selector); const { get, useQuery } = useApi(); const { isLoading, error } = useQuery(['share', shareId], async () => { diff --git a/src/components/hooks/useSticky.js b/src/components/hooks/useSticky.ts similarity index 76% rename from src/components/hooks/useSticky.js rename to src/components/hooks/useSticky.ts index be33f6ed..459c489a 100644 --- a/src/components/hooks/useSticky.js +++ b/src/components/hooks/useSticky.ts @@ -5,8 +5,9 @@ export function useSticky({ enabled = true, threshold = 1 }) { const ref = useRef(null); useEffect(() => { - let observer; - const handler = ([entry]) => setIsSticky(entry.intersectionRatio < threshold); + let observer: IntersectionObserver | undefined; + const handler: IntersectionObserverCallback = ([entry]) => + setIsSticky(entry.intersectionRatio < threshold); if (enabled && ref.current) { observer = new IntersectionObserver(handler, { threshold: [threshold] }); diff --git a/src/components/hooks/useTheme.js b/src/components/hooks/useTheme.ts similarity index 97% rename from src/components/hooks/useTheme.js rename to src/components/hooks/useTheme.ts index 7e40f601..099bf962 100644 --- a/src/components/hooks/useTheme.js +++ b/src/components/hooks/useTheme.ts @@ -4,7 +4,7 @@ import { getItem, setItem } from 'next-basics'; import { THEME_COLORS, THEME_CONFIG } from 'lib/constants'; import { colord } from 'colord'; -const selector = state => state.theme; +const selector = (state: { theme: string }) => state.theme; export function useTheme() { const defaultTheme = diff --git a/src/components/hooks/useTimezone.js b/src/components/hooks/useTimezone.ts similarity index 100% rename from src/components/hooks/useTimezone.js rename to src/components/hooks/useTimezone.ts diff --git a/src/components/hooks/useWebsite.js b/src/components/hooks/useWebsite.ts similarity index 81% rename from src/components/hooks/useWebsite.js rename to src/components/hooks/useWebsite.ts index 5315f0dc..7b68335a 100644 --- a/src/components/hooks/useWebsite.js +++ b/src/components/hooks/useWebsite.ts @@ -1,6 +1,6 @@ import useApi from './useApi'; -export function useWebsite(websiteId) { +export function useWebsite(websiteId: string) { const { get, useQuery } = useApi(); return useQuery(['websites', websiteId], () => get(`/websites/${websiteId}`), { enabled: !!websiteId, diff --git a/tsconfig.json b/tsconfig.json index 9b8b6033..1807e947 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es5", + "target": "es2021", "outDir": "./build", "module": "esnext", "moduleResolution": "node", diff --git a/yarn.lock b/yarn.lock index da4ce1ca..f2ed9264 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7466,10 +7466,10 @@ rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-basics@^0.106.0: - version "0.106.0" - resolved "https://registry.yarnpkg.com/react-basics/-/react-basics-0.106.0.tgz#28ba95a06e6d36adcdb303e1556e6c731b505991" - integrity sha512-CD1qxFu4wrBeNubNo/SkBfWH0BuTErBueNJCCk04IC3qM9poUr3evYfs2S4sfql7dlorcOJ2GflKC1NJ8qPvmw== +react-basics@^0.107.0: + version "0.107.0" + resolved "https://registry.yarnpkg.com/react-basics/-/react-basics-0.107.0.tgz#e5615792cbb3e4707ba5c8f438b29d6a88cf38b3" + integrity sha512-jYnP1z2LTotxXWYwxOBvF26vXxSUBJB0x62YPKkEr1vmJGeg8iOLr8JGF8KE3R6E+NTqzRt6Bmdtt93mjaog4A== dependencies: "@react-spring/web" "^9.7.3" classnames "^2.3.1"