mirror of
https://github.com/umami-software/umami.git
synced 2026-02-04 04:37:11 +01:00
Typescript conversion.
This commit is contained in:
parent
366ef35d3d
commit
8775d696b8
29 changed files with 74 additions and 57 deletions
|
|
@ -98,7 +98,7 @@
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"prisma": "5.4.2",
|
"prisma": "5.4.2",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-basics": "^0.106.0",
|
"react-basics": "^0.107.0",
|
||||||
"react-beautiful-dnd": "^13.1.0",
|
"react-beautiful-dnd": "^13.1.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-error-boundary": "^4.0.4",
|
"react-error-boundary": "^4.0.4",
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { useState } from 'react';
|
||||||
import MobileMenu from './MobileMenu';
|
import MobileMenu from './MobileMenu';
|
||||||
import Icons from 'components/icons';
|
import Icons from 'components/icons';
|
||||||
|
|
||||||
export function HamburgerButton({ menuItems }) {
|
export function HamburgerButton({ menuItems }: { menuItems: any[] }) {
|
||||||
const [active, setActive] = useState(false);
|
const [active, setActive] = useState(false);
|
||||||
|
|
||||||
const handleClick = () => setActive(state => !state);
|
const handleClick = () => setActive(state => !state);
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { useEffect, useState } from 'react';
|
import { ReactNode, useEffect, useState } from 'react';
|
||||||
import { Tooltip } from 'react-basics';
|
import { Tooltip } from 'react-basics';
|
||||||
import styles from './HoverTooltip.module.css';
|
import styles from './HoverTooltip.module.css';
|
||||||
|
|
||||||
export function HoverTooltip({ children }) {
|
export function HoverTooltip({ children }: { children: ReactNode }) {
|
||||||
const [position, setPosition] = useState({ x: -1000, y: -1000 });
|
const [position, setPosition] = useState({ x: -1000, y: -1000 });
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -6,7 +6,7 @@ import { ReactNode } from 'react';
|
||||||
|
|
||||||
export interface LinkButtonProps {
|
export interface LinkButtonProps {
|
||||||
href: string;
|
href: string;
|
||||||
className: string;
|
className?: string;
|
||||||
variant?: string;
|
variant?: string;
|
||||||
scroll?: boolean;
|
scroll?: boolean;
|
||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,19 @@ import { usePathname } from 'next/navigation';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import styles from './MobileMenu.module.css';
|
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 pathname = usePathname();
|
||||||
|
|
||||||
const Items = ({ items, className }) => (
|
const Items = ({ items, className }: { items: any[]; className?: string }) => (
|
||||||
<div className={classNames(styles.items, className)}>
|
<div className={classNames(styles.items, className)}>
|
||||||
{items.map(({ label, url, children }) => {
|
{items.map(({ label, url, children }: { label: string; url: string; children: any[] }) => {
|
||||||
const selected = pathname.startsWith(url);
|
const selected = pathname.startsWith(url);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -3,7 +3,15 @@ import { Button, Icon, Icons } from 'react-basics';
|
||||||
import useMessages from 'components/hooks/useMessages';
|
import useMessages from 'components/hooks/useMessages';
|
||||||
import styles from './Pager.module.css';
|
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 { formatMessage, labels } = useMessages();
|
||||||
const maxPage = pageSize && count ? Math.ceil(count / pageSize) : 0;
|
const maxPage = pageSize && count ? Math.ceil(count / pageSize) : 0;
|
||||||
const lastPage = page === maxPage;
|
const lastPage = page === maxPage;
|
||||||
|
|
@ -13,7 +21,7 @@ export function Pager({ page, pageSize, count, onPageChange, className }) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const handlePageChange = value => {
|
const handlePageChange = (value: number) => {
|
||||||
const nextPage = page + value;
|
const nextPage = page + value;
|
||||||
if (nextPage > 0 && nextPage <= maxPage) {
|
if (nextPage > 0 && nextPage <= maxPage) {
|
||||||
onPageChange(nextPage);
|
onPageChange(nextPage);
|
||||||
1
src/components/declarations.d.ts
vendored
1
src/components/declarations.d.ts
vendored
|
|
@ -1,2 +1,3 @@
|
||||||
declare module '*.css';
|
declare module '*.css';
|
||||||
declare module '*.svg';
|
declare module '*.svg';
|
||||||
|
declare module '*.json';
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,10 @@ const countryNames = {
|
||||||
'en-US': enUS,
|
'en-US': enUS,
|
||||||
};
|
};
|
||||||
|
|
||||||
export function useCountryNames(locale) {
|
export function useCountryNames(locale: string) {
|
||||||
const [list, setList] = useState(countryNames[locale] || enUS);
|
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`);
|
const { data } = await httpGet(`${process.env.basePath}/intl/country/${locale}.json`);
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
|
|
@ -6,7 +6,7 @@ import websiteStore, { setWebsiteDateRange } from 'store/websites';
|
||||||
import appStore, { setDateRange } from 'store/app';
|
import appStore, { setDateRange } from 'store/app';
|
||||||
import useApi from './useApi';
|
import useApi from './useApi';
|
||||||
|
|
||||||
export function useDateRange(websiteId) {
|
export function useDateRange(websiteId: string) {
|
||||||
const { get } = useApi();
|
const { get } = useApi();
|
||||||
const { locale } = useLocale();
|
const { locale } = useLocale();
|
||||||
const websiteConfig = websiteStore(state => state[websiteId]?.dateRange);
|
const websiteConfig = websiteStore(state => state[websiteId]?.dateRange);
|
||||||
|
|
@ -20,7 +20,7 @@ export function useDateRange(websiteId) {
|
||||||
|
|
||||||
if (typeof value === 'string') {
|
if (typeof value === 'string') {
|
||||||
if (value === 'all') {
|
if (value === 'all') {
|
||||||
const result = await get(`/websites/${websiteId}/daterange`);
|
const result: any = await get(`/websites/${websiteId}/daterange`);
|
||||||
const { mindate, maxdate } = result;
|
const { mindate, maxdate } = result;
|
||||||
|
|
||||||
const startDate = new Date(mindate);
|
const startDate = new Date(mindate);
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
export function useDocumentClick(handler) {
|
export function useDocumentClick(handler: (event: MouseEvent) => any) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.addEventListener('click', handler);
|
document.addEventListener('click', handler);
|
||||||
|
|
||||||
|
|
@ -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;
|
|
||||||
21
src/components/hooks/useEscapeKey.ts
Normal file
21
src/components/hooks/useEscapeKey.ts
Normal file
|
|
@ -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;
|
||||||
|
|
@ -9,23 +9,23 @@ export function useFormat() {
|
||||||
const { locale } = useLocale();
|
const { locale } = useLocale();
|
||||||
const countryNames = useCountryNames(locale);
|
const countryNames = useCountryNames(locale);
|
||||||
|
|
||||||
const formatBrowser = value => {
|
const formatBrowser = (value: string) => {
|
||||||
return BROWSERS[value] || value;
|
return BROWSERS[value] || value;
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatCountry = value => {
|
const formatCountry = (value: string) => {
|
||||||
return countryNames[value] || value;
|
return countryNames[value] || value;
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatRegion = value => {
|
const formatRegion = (value: string) => {
|
||||||
return regions[value] ? regions[value] : value;
|
return regions[value] ? regions[value] : value;
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatDevice = value => {
|
const formatDevice = (value: string) => {
|
||||||
return formatMessage(labels[value] || labels.unknown);
|
return formatMessage(labels[value] || labels.unknown);
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatValue = (value, type) => {
|
const formatValue = (value: string, type: string) => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'browser':
|
case 'browser':
|
||||||
return formatBrowser(value);
|
return formatBrowser(value);
|
||||||
|
|
@ -4,13 +4,13 @@ import { messages, labels } from 'components/messages';
|
||||||
export function useMessages() {
|
export function useMessages() {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const getMessage = id => {
|
const getMessage = (id: string) => {
|
||||||
const message = Object.values(messages).find(value => value.id === id);
|
const message = Object.values(messages).find(value => value.id === id);
|
||||||
|
|
||||||
return message ? formatMessage(message) : 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;
|
return descriptor ? intl.formatMessage(descriptor, values, opts) : null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -18,7 +18,7 @@ export function useReport(reportId, defaultParameters) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadReport = async id => {
|
const loadReport = async id => {
|
||||||
const data = await get(`/reports/${id}`);
|
const data: any = await get(`/reports/${id}`);
|
||||||
|
|
||||||
const { dateRange } = data?.parameters || {};
|
const { dateRange } = data?.parameters || {};
|
||||||
const { startDate, endDate } = dateRange || {};
|
const { startDate, endDate } = dateRange || {};
|
||||||
|
|
@ -40,7 +40,7 @@ export function useReport(reportId, defaultParameters) {
|
||||||
const data = await post(`/reports/${type}`, { ...parameters, timezone });
|
const data = await post(`/reports/${type}`, { ...parameters, timezone });
|
||||||
|
|
||||||
setReport(
|
setReport(
|
||||||
produce(state => {
|
produce((state: any) => {
|
||||||
state.parameters = parameters;
|
state.parameters = parameters;
|
||||||
state.data = data;
|
state.data = data;
|
||||||
|
|
||||||
|
|
@ -56,7 +56,7 @@ export function useReport(reportId, defaultParameters) {
|
||||||
const updateReport = useCallback(
|
const updateReport = useCallback(
|
||||||
async data => {
|
async data => {
|
||||||
setReport(
|
setReport(
|
||||||
produce(state => {
|
produce((state: any) => {
|
||||||
const { parameters, ...rest } = data;
|
const { parameters, ...rest } = data;
|
||||||
|
|
||||||
if (parameters) {
|
if (parameters) {
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import useStore, { setShareToken } from 'store/app';
|
import useStore, { setShareToken } from 'store/app';
|
||||||
import useApi from './useApi';
|
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 shareToken = useStore(selector);
|
||||||
const { get, useQuery } = useApi();
|
const { get, useQuery } = useApi();
|
||||||
const { isLoading, error } = useQuery(['share', shareId], async () => {
|
const { isLoading, error } = useQuery(['share', shareId], async () => {
|
||||||
|
|
@ -5,8 +5,9 @@ export function useSticky({ enabled = true, threshold = 1 }) {
|
||||||
const ref = useRef(null);
|
const ref = useRef(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let observer;
|
let observer: IntersectionObserver | undefined;
|
||||||
const handler = ([entry]) => setIsSticky(entry.intersectionRatio < threshold);
|
const handler: IntersectionObserverCallback = ([entry]) =>
|
||||||
|
setIsSticky(entry.intersectionRatio < threshold);
|
||||||
|
|
||||||
if (enabled && ref.current) {
|
if (enabled && ref.current) {
|
||||||
observer = new IntersectionObserver(handler, { threshold: [threshold] });
|
observer = new IntersectionObserver(handler, { threshold: [threshold] });
|
||||||
|
|
@ -4,7 +4,7 @@ import { getItem, setItem } from 'next-basics';
|
||||||
import { THEME_COLORS, THEME_CONFIG } from 'lib/constants';
|
import { THEME_COLORS, THEME_CONFIG } from 'lib/constants';
|
||||||
import { colord } from 'colord';
|
import { colord } from 'colord';
|
||||||
|
|
||||||
const selector = state => state.theme;
|
const selector = (state: { theme: string }) => state.theme;
|
||||||
|
|
||||||
export function useTheme() {
|
export function useTheme() {
|
||||||
const defaultTheme =
|
const defaultTheme =
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import useApi from './useApi';
|
import useApi from './useApi';
|
||||||
|
|
||||||
export function useWebsite(websiteId) {
|
export function useWebsite(websiteId: string) {
|
||||||
const { get, useQuery } = useApi();
|
const { get, useQuery } = useApi();
|
||||||
return useQuery(['websites', websiteId], () => get(`/websites/${websiteId}`), {
|
return useQuery(['websites', websiteId], () => get(`/websites/${websiteId}`), {
|
||||||
enabled: !!websiteId,
|
enabled: !!websiteId,
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"target": "es2021",
|
||||||
"outDir": "./build",
|
"outDir": "./build",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
|
|
|
||||||
|
|
@ -7466,10 +7466,10 @@ rc@^1.2.7:
|
||||||
minimist "^1.2.0"
|
minimist "^1.2.0"
|
||||||
strip-json-comments "~2.0.1"
|
strip-json-comments "~2.0.1"
|
||||||
|
|
||||||
react-basics@^0.106.0:
|
react-basics@^0.107.0:
|
||||||
version "0.106.0"
|
version "0.107.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-basics/-/react-basics-0.106.0.tgz#28ba95a06e6d36adcdb303e1556e6c731b505991"
|
resolved "https://registry.yarnpkg.com/react-basics/-/react-basics-0.107.0.tgz#e5615792cbb3e4707ba5c8f438b29d6a88cf38b3"
|
||||||
integrity sha512-CD1qxFu4wrBeNubNo/SkBfWH0BuTErBueNJCCk04IC3qM9poUr3evYfs2S4sfql7dlorcOJ2GflKC1NJ8qPvmw==
|
integrity sha512-jYnP1z2LTotxXWYwxOBvF26vXxSUBJB0x62YPKkEr1vmJGeg8iOLr8JGF8KE3R6E+NTqzRt6Bmdtt93mjaog4A==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@react-spring/web" "^9.7.3"
|
"@react-spring/web" "^9.7.3"
|
||||||
classnames "^2.3.1"
|
classnames "^2.3.1"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue