diff --git a/assets/arrow-right.svg b/assets/arrow-right.svg deleted file mode 100644 index efc5d74a..00000000 --- a/assets/arrow-right.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/arrow-up-right-from-square.svg b/assets/arrow-up-right-from-square.svg deleted file mode 100644 index 8f6de672..00000000 --- a/assets/arrow-up-right-from-square.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/buoy.svg b/assets/buoy.svg deleted file mode 100644 index 847a814e..00000000 --- a/assets/buoy.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/card.svg b/assets/card.svg deleted file mode 100644 index ecda0e46..00000000 --- a/assets/card.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/chart-bar.svg b/assets/chart-bar.svg deleted file mode 100644 index 36820b76..00000000 --- a/assets/chart-bar.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/check.svg b/assets/check.svg deleted file mode 100644 index 65810c19..00000000 --- a/assets/check.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/chevron-down.svg b/assets/chevron-down.svg deleted file mode 100644 index 69add632..00000000 --- a/assets/chevron-down.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/code.svg b/assets/code.svg deleted file mode 100644 index 0f8e0814..00000000 --- a/assets/code.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/edit.svg b/assets/edit.svg deleted file mode 100644 index b93e50ae..00000000 --- a/assets/edit.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/ellipsis-h.svg b/assets/ellipsis-h.svg deleted file mode 100644 index 5bb08359..00000000 --- a/assets/ellipsis-h.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/exclamation-triangle.svg b/assets/exclamation-triangle.svg deleted file mode 100644 index 46bef5bc..00000000 --- a/assets/exclamation-triangle.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/external-link.svg b/assets/external-link.svg deleted file mode 100644 index e24896b0..00000000 --- a/assets/external-link.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/list-ul.svg b/assets/list-ul.svg deleted file mode 100644 index 5e632126..00000000 --- a/assets/list-ul.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/pen.svg b/assets/pen.svg deleted file mode 100644 index b2979420..00000000 --- a/assets/pen.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/plus.svg b/assets/plus.svg deleted file mode 100644 index e4774d87..00000000 --- a/assets/plus.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/times.svg b/assets/times.svg deleted file mode 100644 index 261bb277..00000000 --- a/assets/times.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/trash.svg b/assets/trash.svg deleted file mode 100644 index 2f525c8f..00000000 --- a/assets/trash.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/xmark.svg b/assets/xmark.svg deleted file mode 100644 index 83bd5740..00000000 --- a/assets/xmark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/components/buttons/LanguageButton.js b/components/buttons/LanguageButton.js index b83596e4..ed9c6682 100644 --- a/components/buttons/LanguageButton.js +++ b/components/buttons/LanguageButton.js @@ -1,30 +1,51 @@ +import { Icon, Button, PopupTrigger, Popup, Tooltip, Icons, Text } from 'react-basics'; +import { useIntl } from 'react-intl'; +import classNames from 'classnames'; import { languages } from 'lib/lang'; import useLocale from 'hooks/useLocale'; -import MenuButton from 'components/common/MenuButton'; -import Globe from 'assets/globe.svg'; +import { Globe } from 'components/icons'; +import { labels } from 'components/messages'; import styles from './LanguageButton.module.css'; -import { Icon } from 'react-basics'; -export default function LanguageButton() { +export default function LanguageButton({ tooltipPosition = 'top' }) { + const { formatMessage } = useIntl(); const { locale, saveLocale } = useLocale(); - const menuOptions = Object.keys(languages).map(key => ({ ...languages[key], value: key })); + const items = Object.keys(languages).map(key => ({ ...languages[key], value: key })); function handleSelect(value) { saveLocale(value); } return ( - - - - - + + + + {formatMessage(labels.language)} + + +
+ {items.map(({ value, label }) => { + return ( +
+ {label} + {value === locale && ( + + + + )} +
+ ); + })} +
+
+
); } diff --git a/components/buttons/LanguageButton.module.css b/components/buttons/LanguageButton.module.css index 9cb18326..bf51b571 100644 --- a/components/buttons/LanguageButton.module.css +++ b/components/buttons/LanguageButton.module.css @@ -1,25 +1,35 @@ .menu { display: flex; flex-flow: row wrap; - min-width: 560px; + min-width: 600px; max-width: 100vw; padding: 10px; -} - -.menu div { + background: var(--base50); + z-index: var(--z-index100); border-radius: 5px; + border: 1px solid var(--border-color); + margin-left: 10px; +} + +.item { + display: flex; + align-items: center; + justify-content: space-between; min-width: calc(100% / 3); + border-radius: 5px; + padding: 5px 10px; } -@media only screen and (max-width: 992px) { - .menu { - min-width: 90vw; - transform: translateX(calc(40vw)); - } +.item:hover { + background: var(--base75); + cursor: pointer; } -@media only screen and (max-width: 768px) { - .menu div { - min-width: 50%; - } +.selected { + font-weight: 700; + background: var(--blue100); +} + +.icon { + color: var(--primary400); } diff --git a/components/buttons/LogoutButton.js b/components/buttons/LogoutButton.js new file mode 100644 index 00000000..f6f2450e --- /dev/null +++ b/components/buttons/LogoutButton.js @@ -0,0 +1,22 @@ +import { Button, Icon, Icons, PopupTrigger, Tooltip } from 'react-basics'; +import Link from 'next/link'; +import { labels } from 'components/messages'; +import { useIntl } from 'react-intl'; + +export default function LogoutButton({ tooltipPosition = 'top' }) { + const { formatMessage } = useIntl(); + return ( + + + + + {formatMessage(labels.logout)} + + + + ); +} diff --git a/components/buttons/ThemeButton.js b/components/buttons/ThemeButton.js index ed517596..f3d91e4f 100644 --- a/components/buttons/ThemeButton.js +++ b/components/buttons/ThemeButton.js @@ -1,12 +1,14 @@ import { useTransition, animated } from 'react-spring'; +import { Button, Icon, PopupTrigger, Tooltip } from 'react-basics'; +import { useIntl } from 'react-intl'; import useTheme from 'hooks/useTheme'; -import Sun from 'assets/sun.svg'; -import Moon from 'assets/moon.svg'; +import { Sun, Moon } from 'components/icons'; +import { labels } from 'components/messages'; import styles from './ThemeButton.module.css'; -import { Icon } from 'react-basics'; -export default function ThemeButton() { +export default function ThemeButton({ tooltipPosition = 'top' }) { const [theme, setTheme] = useTheme(); + const { formatMessage } = useIntl(); const transitions = useTransition(theme, { initial: { opacity: 1 }, @@ -14,7 +16,7 @@ export default function ThemeButton() { opacity: 0, transform: `translateY(${theme === 'light' ? '20px' : '-20px'}) scale(0.5)`, }, - enter: { opacity: 1, transform: 'translateY(0px) scale(1)' }, + enter: { opacity: 1, transform: 'translateY(0px) scale(1.0)' }, leave: { opacity: 0, transform: `translateY(${theme === 'light' ? '-20px' : '20px'}) scale(0.5)`, @@ -26,12 +28,15 @@ export default function ThemeButton() { } return ( -
- {transitions((styles, item) => ( - - {item === 'light' ? : } - - ))} -
+ + + {formatMessage(labels.theme)} + ); } diff --git a/components/buttons/ThemeButton.module.css b/components/buttons/ThemeButton.module.css index efde6842..3f7c705a 100644 --- a/components/buttons/ThemeButton.module.css +++ b/components/buttons/ThemeButton.module.css @@ -5,9 +5,11 @@ justify-content: center; align-items: center; cursor: pointer; - padding-bottom: 3px; } -.button svg { +.button > div { + display: flex; + justify-content: center; + align-items: center; position: absolute; } diff --git a/components/common/Calendar.js b/components/common/Calendar.js index 9fcd26dc..dd771f28 100644 --- a/components/common/Calendar.js +++ b/components/common/Calendar.js @@ -16,13 +16,11 @@ import { isBefore, isAfter, } from 'date-fns'; -import { Button, Icon } from 'react-basics'; +import { Button, Icon, Icons } from 'react-basics'; import { chunkArray } from 'next-basics'; import useLocale from 'hooks/useLocale'; import { dateFormat } from 'lib/date'; import { getDateLocale } from 'lib/lang'; -import Chevron from 'assets/chevron-down.svg'; -import Cross from 'assets/times.svg'; import styles from './Calendar.module.css'; export default function Calendar({ date, minDate, maxDate, onChange }) { @@ -61,7 +59,7 @@ export default function Calendar({ date, minDate, maxDate, onChange }) { > {month} - {selectMonth ? : } + {selectMonth ? : }
{year} - {selectMonth ? : } + {selectMonth ? : }
@@ -239,7 +237,7 @@ const YearSelector = ({ date, minDate, maxDate, onSelect }) => { variant="light" > - + @@ -273,7 +271,7 @@ const YearSelector = ({ date, minDate, maxDate, onSelect }) => { variant="light" > - + diff --git a/components/common/EmptyPlaceholder.js b/components/common/EmptyPlaceholder.js index 1b6617e3..fa773a01 100644 --- a/components/common/EmptyPlaceholder.js +++ b/components/common/EmptyPlaceholder.js @@ -1,13 +1,13 @@ import { Icon, Text, Flexbox } from 'react-basics'; import Logo from 'assets/logo.svg'; -function EmptyPlaceholder({ msg, children }) { +function EmptyPlaceholder({ message, children }) { return ( - {msg} + {message}
{children}
); diff --git a/components/common/ErrorMessage.js b/components/common/ErrorMessage.js index 2a411425..ccd96c80 100644 --- a/components/common/ErrorMessage.js +++ b/components/common/ErrorMessage.js @@ -1,13 +1,12 @@ -import Exclamation from 'assets/exclamation-triangle.svg'; import { FormattedMessage } from 'react-intl'; +import { Icon, Icons } from 'react-basics'; import styles from './ErrorMessage.module.css'; -import { Icon } from 'react-basics'; export default function ErrorMessage() { return (
- +
diff --git a/components/common/EventDataButton.js b/components/common/EventDataButton.js index 683bcf20..5393d7d5 100644 --- a/components/common/EventDataButton.js +++ b/components/common/EventDataButton.js @@ -1,8 +1,7 @@ -import List from 'assets/list-ul.svg'; import EventDataForm from 'components/metrics/EventDataForm'; import PropTypes from 'prop-types'; import { useState } from 'react'; -import { Button, Icon, Modal } from 'react-basics'; +import { Button, Icon, Modal, Icons } from 'react-basics'; import { FormattedMessage } from 'react-intl'; import styles from './EventDataButton.module.css'; @@ -29,7 +28,7 @@ function EventDataButton({ websiteId }) { className={styles.button} > - + Event Data diff --git a/components/icons.js b/components/icons.js index 277c5e0f..0766dcb8 100644 --- a/components/icons.js +++ b/components/icons.js @@ -1,7 +1,7 @@ +import Bolt from 'assets/bolt.svg'; import Calendar from 'assets/calendar.svg'; import Clock from 'assets/clock.svg'; import Dashboard from 'assets/dashboard.svg'; -import Edit from 'assets/edit.svg'; import Gear from 'assets/gear.svg'; import Globe from 'assets/globe.svg'; import Lock from 'assets/lock.svg'; @@ -9,15 +9,14 @@ import Logo from 'assets/logo.svg'; import Moon from 'assets/moon.svg'; import Profile from 'assets/profile.svg'; import Sun from 'assets/sun.svg'; -import Trash from 'assets/trash.svg'; import User from 'assets/user.svg'; import Users from 'assets/users.svg'; export { + Bolt, Calendar, Clock, Dashboard, - Edit, Gear, Globe, Lock, @@ -25,7 +24,6 @@ export { Moon, Profile, Sun, - Trash, User, Users, }; diff --git a/components/layout/NavBar.js b/components/layout/NavBar.js index 3df4a68f..bc4d3d44 100644 --- a/components/layout/NavBar.js +++ b/components/layout/NavBar.js @@ -1,29 +1,32 @@ import { useState } from 'react'; +import { useIntl } from 'react-intl'; import { Icon, Text, Icons } from 'react-basics'; import classNames from 'classnames'; import { Dashboard, Logo, Profile, User, Users, Clock, Globe } from 'components/icons'; +import ThemeButton from '../buttons/ThemeButton'; +import LanguageButton from 'components/buttons/LanguageButton'; +import LogoutButton from 'components/buttons/LogoutButton'; +import { labels } from 'components/messages'; import NavGroup from './NavGroup'; import styles from './NavBar.module.css'; -import ThemeButton from '../buttons/ThemeButton'; -import LanguageButton from '../buttons/LanguageButton'; - -const { ChevronDown, Search } = Icons; - -const analytics = [ - { label: 'Dashboard', url: '/dashboard', icon: }, - { label: 'Realtime', url: '/realtime', icon: }, - { label: 'Queries', url: '/queries', icon: }, -]; - -const settings = [ - { label: 'Websites', url: '/settings/websites', icon: }, - { label: 'Users', url: '/settings/users', icon: }, - { label: 'Teams', url: '/settings/teams', icon: }, - { label: 'Profile', url: '/settings/profile', icon: }, -]; export default function NavBar() { + const { formatMessage } = useIntl(); const [minimized, setMinimized] = useState(false); + const tooltipPosition = minimized ? 'right' : 'top'; + + const analytics = [ + { label: formatMessage(labels.dashboard), url: '/dashboard', icon: }, + { label: formatMessage(labels.realtime), url: '/realtime', icon: }, + { label: formatMessage(labels.queries), url: '/queries', icon: }, + ]; + + const settings = [ + { label: formatMessage(labels.websites), url: '/settings/websites', icon: }, + { label: formatMessage(labels.users), url: '/settings/users', icon: }, + { label: formatMessage(labels.teams), url: '/settings/teams', icon: }, + { label: formatMessage(labels.profile), url: '/settings/profile', icon: }, + ]; const handleMinimize = () => setMinimized(state => !state); @@ -35,15 +38,16 @@ export default function NavBar() { umami - + - - + +
- - + + +
diff --git a/components/layout/NavBar.module.css b/components/layout/NavBar.module.css index 19a332df..6610e602 100644 --- a/components/layout/NavBar.module.css +++ b/components/layout/NavBar.module.css @@ -51,3 +51,7 @@ align-items: center; justify-content: center; } + +.minimized .buttons { + flex-direction: column; +} diff --git a/components/layout/NavGroup.js b/components/layout/NavGroup.js index 44cd4a96..b2d6d392 100644 --- a/components/layout/NavGroup.js +++ b/components/layout/NavGroup.js @@ -5,8 +5,6 @@ import { useRouter } from 'next/router'; import Link from 'next/link'; import styles from './NavGroup.module.css'; -const { ChevronDown } = Icons; - export default function NavGroup({ title, items, @@ -30,7 +28,7 @@ export default function NavGroup({
{title} - +
)} diff --git a/components/messages.js b/components/messages.js index a5683d20..53fbea23 100644 --- a/components/messages.js +++ b/components/messages.js @@ -52,17 +52,24 @@ export const labels = defineMessages({ language: { id: 'label.language', defaultMessage: 'Language' }, theme: { id: 'label.theme', defaultMessage: 'Theme' }, profile: { id: 'label.profile', defaultMessage: 'Profile' }, + dashboard: { id: 'label.dashboard', defaultMessage: 'Dashboard' }, + more: { id: 'label.more', defaultMessage: 'More' }, + realtime: { id: 'label.realtime', defaultMessage: 'Realtime' }, + queries: { id: 'label.queries', defaultMessage: 'Queries' }, + teams: { id: 'label.teams', defaultMessage: 'Teams' }, + analytics: { id: 'label.analytics', defaultMessage: 'Analytics' }, + logout: { id: 'label.logout', defaultMessage: 'Logout' }, }); export const messages = defineMessages({ error: { id: 'message.error', defaultMessage: 'Something went wrong.' }, - saved: { id: 'message.saved', defaultMessage: 'Saved successfully.' }, + saved: { id: 'message.saved', defaultMessage: 'Saved.' }, noUsers: { id: 'message.no-users', defaultMessage: 'There are no users.' }, - userDeleted: { id: 'message.user-deleted', defaultMessage: 'User deleted successfully.' }, + userDeleted: { id: 'message.user-deleted', defaultMessage: 'User deleted.' }, noData: { id: 'message.no-data', defaultMessage: 'No data available.' }, deleteUserWarning: { id: 'message.delete-user-warning', - defaultMessage: 'Are you sure you want to delete {username}?', + defaultMessage: 'Are you sure you want to delete the user {username}?', }, minPasswordLength: { id: 'message.min-password-length', @@ -79,7 +86,7 @@ export const messages = defineMessages({ trackingCode: { id: 'message.tracking-code', defaultMessage: - 'To track stats for this website, place the following code in the section of your HTML.', + 'To track stats for this website, place the following code in the ... section of your HTML.', }, deleteWebsite: { id: 'message.delete-website', @@ -107,6 +114,10 @@ export const messages = defineMessages({ defaultMessage: 'You do not have any websites configured.', }, noMatchPassword: { id: 'message.no-match-password', defaultMessage: 'Passwords do not match.' }, + goToSettings: { + id: 'message.go-to-settings', + defaultMessage: 'Go to settings', + }, }); export const devices = defineMessages({ diff --git a/components/metrics/FilterTags.js b/components/metrics/FilterTags.js index 315d2a22..75d38371 100644 --- a/components/metrics/FilterTags.js +++ b/components/metrics/FilterTags.js @@ -1,7 +1,6 @@ import classNames from 'classnames'; import { safeDecodeURI } from 'next-basics'; -import { Button, Icon } from 'react-basics'; -import Times from 'assets/times.svg'; +import { Button, Icon, Icons } from 'react-basics'; import styles from './FilterTags.module.css'; export default function FilterTags({ className, params, onClick }) { @@ -19,7 +18,7 @@ export default function FilterTags({ className, params, onClick }) { diff --git a/components/pages/dashboard/Dashboard.js b/components/pages/dashboard/Dashboard.js index 523f04c2..01faa128 100644 --- a/components/pages/dashboard/Dashboard.js +++ b/components/pages/dashboard/Dashboard.js @@ -1,53 +1,62 @@ import { useState } from 'react'; -import { Button, Loading } from 'react-basics'; -import { defineMessages, useIntl } from 'react-intl'; +import { Button, Icon, Icons, Text, Flexbox } from 'react-basics'; +import { useIntl } from 'react-intl'; +import Link from 'next/link'; import Page from 'components/layout/Page'; import PageHeader from 'components/layout/PageHeader'; import WebsiteChartList from 'components/pages/websites/WebsiteChartList'; import DashboardSettingsButton from 'components/pages/dashboard/DashboardSettingsButton'; import DashboardEdit from 'components/pages/dashboard/DashboardEdit'; -import styles from 'components/pages/websites/WebsiteList.module.css'; -import useUser from 'hooks/useUser'; +import EmptyPlaceholder from 'components/common/EmptyPlaceholder'; import useApi from 'hooks/useApi'; +import { labels, messages } from 'components/messages'; import useDashboard from 'store/dashboard'; -const messages = defineMessages({ - dashboard: { id: 'label.dashboard', defaultMessage: 'Dashboard' }, - more: { id: 'label.more', defaultMessage: 'More' }, -}); - export default function Dashboard({ userId }) { - const { user } = useUser(); const dashboard = useDashboard(); const { showCharts, limit, editing } = dashboard; const [max, setMax] = useState(limit); const { get, useQuery } = useApi(); - const { data, isLoading } = useQuery(['websites'], () => get('/websites', { userId })); + const { data, isLoading, error } = useQuery(['websites'], () => get('/websites', { userId })); const { formatMessage } = useIntl(); + const hasData = data && data.length !== 0; function handleMore() { setMax(max + limit); } - if (!user || isLoading) { - return ; - } - - if (!data) { - return null; - } - return ( - - - {!editing && } + + + {!editing && hasData && } - {editing && } - {!editing && } - {max < data.length && ( - + {!hasData && ( + + + + + + )} + {hasData && ( + <> + {editing && } + {!editing && } + {max < data.length && ( + + + + )} + )} ); diff --git a/components/pages/settings/account/AccountDetails.js b/components/pages/settings/account/AccountDetails.js deleted file mode 100644 index 4ebd329f..00000000 --- a/components/pages/settings/account/AccountDetails.js +++ /dev/null @@ -1,69 +0,0 @@ -import { Button, Modal, useToast, Icon, Tabs, Item } from 'react-basics'; -import { useEffect, useState } from 'react'; -import useApi from 'hooks/useApi'; -import PasswordEditForm from 'components/pages/settings/account/PasswordEditForm'; -import PageHeader from 'components/layout/PageHeader'; -import AccountEditForm from 'components/pages/settings/account/AccountEditForm'; -import Lock from 'assets/lock.svg'; -import Page from 'components/layout/Page'; -import ApiKeysList from 'components/pages/settings/account/ApiKeysList'; -import useUser from 'hooks/useUser'; - -export default function AccountDetails() { - const { user } = useUser(); - const [values, setValues] = useState(null); - const [tab, setTab] = useState('detail'); - const [showForm, setShowForm] = useState(false); - const { get, useQuery } = useApi(); - const { data, isLoading } = useQuery(['account'], () => get(`/accounts/${user.id}`), { - cacheTime: 0, - }); - const { toast, showToast } = useToast(); - - const handleChangePassword = () => setShowForm(true); - - const handleClose = () => { - setShowForm(false); - }; - - const handleSave = data => { - setValues(data); - showToast({ message: 'Saved successfully.', variant: 'success' }); - }; - - const handlePasswordSave = () => { - setShowForm(false); - showToast({ message: 'Password successfully changed', variant: 'success' }); - }; - - useEffect(() => { - if (data) { - setValues(data); - } - }, [data]); - - return ( - - {toast} - - - - - Details - API Keys - - {tab === 'detail' && } - {tab === 'apiKey' && } - {data && showForm && ( - - {close => } - - )} - - ); -} diff --git a/components/pages/settings/account/AccountEditForm.js b/components/pages/settings/account/AccountEditForm.js deleted file mode 100644 index 6f4ce184..00000000 --- a/components/pages/settings/account/AccountEditForm.js +++ /dev/null @@ -1,39 +0,0 @@ -import { Form, FormRow, FormButtons, FormInput, TextField, SubmitButton } from 'react-basics'; -import { useRef } from 'react'; -import useApi from 'hooks/useApi'; - -export default function AccountEditForm({ data, onSave }) { - const { id } = data; - const { post, useMutation } = useApi(); - const { mutate, error } = useMutation(({ name }) => post(`/accounts/${id}`, { name })); - const ref = useRef(null); - - const handleSubmit = async data => { - mutate(data, { - onSuccess: async () => { - onSave(data); - ref.current.reset(data); - }, - }); - }; - - return ( - <> -
- - - - - - - - - - - - Save - -
- - ); -} diff --git a/components/pages/settings/account/ApiKeyDeleteForm.js b/components/pages/settings/account/ApiKeyDeleteForm.js deleted file mode 100644 index ec5abdc8..00000000 --- a/components/pages/settings/account/ApiKeyDeleteForm.js +++ /dev/null @@ -1,29 +0,0 @@ -import useApi from 'hooks/useApi'; -import { Button, Form, FormButtons, SubmitButton } from 'react-basics'; - -export default function ApiKeyDeleteForm({ apiKeyId, onSave, onClose }) { - const { del, useMutation } = useApi(); - const { mutate, error, isLoading } = useMutation(data => del(`/api-key/${apiKeyId}`, data)); - - const handleSubmit = async data => { - mutate(data, { - onSuccess: async () => { - onSave(); - }, - }); - }; - - return ( -
-
Are you sure you want to delete this API KEY?
- - - Delete - - - -
- ); -} diff --git a/components/pages/settings/account/ApiKeysList.js b/components/pages/settings/account/ApiKeysList.js deleted file mode 100644 index 6211a2b2..00000000 --- a/components/pages/settings/account/ApiKeysList.js +++ /dev/null @@ -1,46 +0,0 @@ -import { Text, Icon, useToast, Banner, LoadingButton, Loading } from 'react-basics'; -import useApi from 'hooks/useApi'; -import ApiKeysTable from 'components/pages/settings/account/ApiKeysTable'; - -export default function ApiKeysList() { - const { toast, showToast } = useToast(); - const { get, post, useQuery, useMutation } = useApi(); - const { mutate, isLoading: isUpdating } = useMutation(data => post('/api-key', data)); - const { data, refetch, isLoading, error } = useQuery(['api-key'], () => get(`/api-key`)); - const hasData = data && data.length !== 0; - - const handleCreate = () => { - mutate( - {}, - { - onSuccess: async () => { - showToast({ message: 'API key saved.', variant: 'success' }); - await handleSave(); - }, - }, - ); - }; - - const handleSave = async () => { - await refetch(); - }; - - if (error) { - return Something went wrong.; - } - - if (isLoading) { - return ; - } - - return ( - <> - {toast} - - Create key - - {hasData && } - {!hasData && You don't have any API keys.} - - ); -} diff --git a/components/pages/settings/account/ApiKeysTable.js b/components/pages/settings/account/ApiKeysTable.js deleted file mode 100644 index 236e76af..00000000 --- a/components/pages/settings/account/ApiKeysTable.js +++ /dev/null @@ -1,100 +0,0 @@ -import { formatDistance } from 'date-fns'; -import { useState } from 'react'; -import { - Button, - Icon, - Modal, - PasswordField, - Table, - TableBody, - TableCell, - TableColumn, - TableHeader, - TableRow, - Text, -} from 'react-basics'; -import ApiKeyDeleteForm from 'components/pages/settings/account/ApiKeyDeleteForm'; -import Trash from 'assets/trash.svg'; -import styles from './ApiKeysTable.module.css'; - -const columns = [ - { name: 'apiKey', label: 'Key', style: { flex: 3 } }, - { name: 'created', label: 'Created', style: { flex: 1 } }, - { name: 'action', label: ' ', style: { flex: 1 } }, -]; - -export default function ApiKeysTable({ data = [], onSave }) { - const [apiKeyId, setApiKeyId] = useState(null); - - const handleSave = () => { - setApiKeyId(null); - onSave(); - }; - - const handleClose = () => { - setApiKeyId(null); - }; - - const handleDelete = id => { - setApiKeyId(id); - }; - - return ( - <> - - - {(column, index) => { - return ( - - {column.label} - - ); - }} - - - {(row, keys, rowIndex) => { - row.apiKey = ; - - row.created = formatDistance(new Date(row.createdAt), new Date(), { - addSuffix: true, - }); - - row.action = ( - - ); - - return ( - - {(data, key, colIndex) => { - return ( - - {data[key]} - - ); - }} - - ); - }} - -
- {apiKeyId && ( - - {close => } - - )} - - ); -} diff --git a/components/pages/settings/account/ApiKeysTable.module.css b/components/pages/settings/account/ApiKeysTable.module.css deleted file mode 100644 index cc2feee5..00000000 --- a/components/pages/settings/account/ApiKeysTable.module.css +++ /dev/null @@ -1,31 +0,0 @@ -.table th, -.table td { - flex: 2; -} - -.cell { - display: flex; - align-items: center; -} - -.header:first-child, -.cell:first-child { - min-width: 320px; -} - -.input { - flex: 2; -} - -.cell:last-child { - justify-content: flex-end; -} - -.actions { - display: flex; - gap: 12px; -} - -.empty { - min-height: 300px; -} diff --git a/components/pages/settings/account/PasswordEditForm.js b/components/pages/settings/account/PasswordEditForm.js deleted file mode 100644 index 17cc8447..00000000 --- a/components/pages/settings/account/PasswordEditForm.js +++ /dev/null @@ -1,67 +0,0 @@ -import { useRef } from 'react'; -import { Form, FormRow, FormInput, FormButtons, PasswordField, Button } from 'react-basics'; -import useApi from 'hooks/useApi'; -import useUser from 'hooks/useUser'; - -export default function PasswordEditForm({ onSave, onClose }) { - const { post, useMutation } = useApi(); - const { user } = useUser(); - const { mutate, error, isLoading } = useMutation(data => - post(`/accounts/${user.id}/change-password`, data), - ); - const ref = useRef(null); - - const handleSubmit = async data => { - mutate(data, { - onSuccess: async () => { - onSave(); - }, - }); - }; - - const samePassword = value => { - if (value !== ref?.current?.getValues('newPassword')) { - return "Passwords don't match"; - } - return true; - }; - - return ( -
- - - - - - - - - - - - - - - - - - - -
- ); -} diff --git a/components/pages/settings/account/PasswordResetForm.js b/components/pages/settings/account/PasswordResetForm.js deleted file mode 100644 index ef562208..00000000 --- a/components/pages/settings/account/PasswordResetForm.js +++ /dev/null @@ -1,50 +0,0 @@ -import { useRef } from 'react'; -import { Form, FormRow, FormInput, FormButtons, PasswordField, SubmitButton } from 'react-basics'; -import useApi from 'hooks/useApi'; - -export default function PasswordResetForm({ token, onSave }) { - const { post, useMutation } = useApi(); - const { mutate, error } = useMutation(data => - post('/accounts/reset-password', { ...data, token }), - ); - const ref = useRef(null); - - const handleSubmit = async data => { - mutate(data, { - onSuccess: async () => { - onSave(); - }, - }); - }; - - const samePassword = value => { - if (value !== ref?.current?.getValues('newPassword')) { - return "Passwords don't match"; - } - return true; - }; - - return ( - <> -
-

Reset your password

- - - - - - - - - - - - Update password - -
- - ); -} diff --git a/components/pages/settings/profile/PasswordChangeButton.js b/components/pages/settings/profile/PasswordChangeButton.js index 26cff377..b085df57 100644 --- a/components/pages/settings/profile/PasswordChangeButton.js +++ b/components/pages/settings/profile/PasswordChangeButton.js @@ -1,5 +1,5 @@ import { useIntl } from 'react-intl'; -import { Button, Icon, Text, useToast, ModalTrigger } from 'react-basics'; +import { Button, Icon, Text, useToast, ModalTrigger, Modal } from 'react-basics'; import PasswordEditForm from 'components/pages/settings/profile/PasswordEditForm'; import { Lock } from 'components/icons'; import { labels, messages } from 'components/messages'; @@ -22,7 +22,7 @@ export default function PasswordChangeButton() { {formatMessage(labels.changePassword)} - {close => } + {close => } ); diff --git a/components/pages/settings/profile/PasswordEditForm.js b/components/pages/settings/profile/PasswordEditForm.js index c11c96f4..be3d1048 100644 --- a/components/pages/settings/profile/PasswordEditForm.js +++ b/components/pages/settings/profile/PasswordEditForm.js @@ -14,6 +14,7 @@ export default function PasswordEditForm({ onSave, onClose }) { mutate(data, { onSuccess: async () => { onSave(); + onClose(); }, }); }; diff --git a/components/pages/settings/profile/ProfileDetails.js b/components/pages/settings/profile/ProfileDetails.js index 346ca17a..cc030233 100644 --- a/components/pages/settings/profile/ProfileDetails.js +++ b/components/pages/settings/profile/ProfileDetails.js @@ -3,7 +3,7 @@ import { useIntl } from 'react-intl'; import TimezoneSetting from 'components/pages/settings/profile/TimezoneSetting'; import DateRangeSetting from 'components/pages/settings/profile/DateRangeSetting'; import LanguageSetting from 'components/pages/settings/profile/LanguageSetting'; -import ThemeSetting from 'components/buttons/ThemeSetting'; +import ThemeSetting from 'components/pages/settings/profile/ThemeSetting'; import useUser from 'hooks/useUser'; import { labels } from 'components/messages'; @@ -21,13 +21,13 @@ export default function ProfileDetails() {
{username} {role} - + - + - + diff --git a/components/buttons/ThemeSetting.js b/components/pages/settings/profile/ThemeSetting.js similarity index 100% rename from components/buttons/ThemeSetting.js rename to components/pages/settings/profile/ThemeSetting.js diff --git a/components/buttons/ThemeSetting.module.css b/components/pages/settings/profile/ThemeSetting.module.css similarity index 100% rename from components/buttons/ThemeSetting.module.css rename to components/pages/settings/profile/ThemeSetting.module.css diff --git a/components/pages/settings/teams/TeamAddForm.js b/components/pages/settings/teams/TeamAddForm.js index 7ee3b985..fd55c93c 100644 --- a/components/pages/settings/teams/TeamAddForm.js +++ b/components/pages/settings/teams/TeamAddForm.js @@ -22,6 +22,7 @@ export default function TeamAddForm({ onSave, onClose }) { mutate(data, { onSuccess: async () => { onSave(); + onClose(); }, }); }; @@ -29,7 +30,7 @@ export default function TeamAddForm({ onSave, onClose }) { return ( - + diff --git a/components/pages/settings/teams/TeamEditForm.js b/components/pages/settings/teams/TeamEditForm.js index 5b19a0ef..47bc5920 100644 --- a/components/pages/settings/teams/TeamEditForm.js +++ b/components/pages/settings/teams/TeamEditForm.js @@ -47,7 +47,7 @@ export default function TeamEditForm({ teamId, data, onSave }) { - + diff --git a/components/pages/settings/teams/TeamMembersTable.js b/components/pages/settings/teams/TeamMembersTable.js index a90d2d6d..0f55153c 100644 --- a/components/pages/settings/teams/TeamMembersTable.js +++ b/components/pages/settings/teams/TeamMembersTable.js @@ -11,11 +11,9 @@ import { Flexbox, Text, } from 'react-basics'; +import { useIntl } from 'react-intl'; import { ROLES } from 'lib/constants'; import { labels } from 'components/messages'; -import { useIntl } from 'react-intl'; - -const { Close } = Icons; export default function TeamMembersTable({ data = [] }) { const { formatMessage } = useIntl(); @@ -48,7 +46,7 @@ export default function TeamMembersTable({ data = [] }) {
diff --git a/components/pages/settings/teams/TeamWebsites.js b/components/pages/settings/teams/TeamWebsites.js index f611fbbb..f00ee057 100644 --- a/components/pages/settings/teams/TeamWebsites.js +++ b/components/pages/settings/teams/TeamWebsites.js @@ -7,7 +7,7 @@ import { messages } from 'components/messages'; export default function TeamWebsites({ teamId }) { const { formatMessage } = useIntl(); const { get, useQuery } = useApi(); - const { data, isLoading } = useQuery(['team/websites', teamId], () => + const { data, isLoading } = useQuery(['teams/websites', teamId], () => get(`/teams/${teamId}/websites`), ); const hasData = data && data.length !== 0; diff --git a/components/pages/settings/teams/TeamsList.js b/components/pages/settings/teams/TeamsList.js index fab1bc38..cae33567 100644 --- a/components/pages/settings/teams/TeamsList.js +++ b/components/pages/settings/teams/TeamsList.js @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { Button, Icon, Modal, useToast, Icons, Text } from 'react-basics'; +import { Button, Icon, Modal, ModalTrigger, useToast, Icons, Text } from 'react-basics'; import { useIntl } from 'react-intl'; import useApi from 'hooks/useApi'; import EmptyPlaceholder from 'components/common/EmptyPlaceholder'; @@ -9,58 +9,43 @@ import TeamsTable from 'components/pages/settings/teams/TeamsTable'; import Page from 'components/layout/Page'; import { labels, messages } from 'components/messages'; -const { Plus } = Icons; - export default function TeamsList() { const { formatMessage } = useIntl(); - const [edit, setEdit] = useState(false); const [update, setUpdate] = useState(0); const { get, useQuery } = useApi(); const { data, isLoading, error } = useQuery(['teams', update], () => get(`/teams`)); const hasData = data && data.length !== 0; const { toast, showToast } = useToast(); - const handleAdd = () => { - setEdit(true); - }; - const handleSave = () => { - setEdit(false); setUpdate(state => state + 1); showToast({ message: formatMessage(messages.saved), variant: 'success' }); }; - const handleClose = () => { - setEdit(false); - }; + const createButton = ( + + + + {close => } + + + ); return ( {toast} - - - + {createButton} {hasData && } {!hasData && ( - + {createButton} )} - {edit && ( - - {close => } - - )} ); } diff --git a/components/pages/settings/teams/TeamsTable.js b/components/pages/settings/teams/TeamsTable.js index ae4c0116..73cf0eb2 100644 --- a/components/pages/settings/teams/TeamsTable.js +++ b/components/pages/settings/teams/TeamsTable.js @@ -15,8 +15,6 @@ import { import { useIntl } from 'react-intl'; import { labels } from 'components/messages'; -const { ArrowRight } = Icons; - export default function TeamsTable({ data = [] }) { const { formatMessage } = useIntl(); @@ -46,7 +44,7 @@ export default function TeamsTable({ data = [] }) { diff --git a/components/pages/settings/users/UserAddButton.js b/components/pages/settings/users/UserAddButton.js index 7f1ba624..08600a2e 100644 --- a/components/pages/settings/users/UserAddButton.js +++ b/components/pages/settings/users/UserAddButton.js @@ -1,44 +1,26 @@ -import { useState } from 'react'; import { useIntl } from 'react-intl'; -import { Button, Icon, Text, Modal, useToast, Icons } from 'react-basics'; +import { Button, Icon, Text, Modal, Icons, ModalTrigger } from 'react-basics'; import UserAddForm from './UserAddForm'; -import { labels, messages } from 'components/messages'; - -const { Plus } = Icons; +import { labels } from 'components/messages'; export default function UserAddButton({ onSave }) { const { formatMessage } = useIntl(); - const [edit, setEdit] = useState(false); - const { toast, showToast } = useToast(); const handleSave = () => { - showToast({ message: formatMessage(messages.saved), variant: 'success' }); - setEdit(false); onSave(); }; - const handleAdd = () => { - setEdit(true); - }; - - const handleClose = () => { - setEdit(false); - }; - return ( - <> - {toast} - - {edit && ( - - - - )} - + + {close => } + + ); } diff --git a/components/pages/settings/users/UserAddForm.js b/components/pages/settings/users/UserAddForm.js index efa04b65..cba5b7cd 100644 --- a/components/pages/settings/users/UserAddForm.js +++ b/components/pages/settings/users/UserAddForm.js @@ -24,6 +24,7 @@ export default function UserAddForm({ onSave, onClose }) { mutate(data, { onSuccess: async () => { onSave(data); + onClose(); }, }); }; diff --git a/components/pages/settings/users/UserDeleteForm.js b/components/pages/settings/users/UserDeleteForm.js index a464ae4f..ffed7556 100644 --- a/components/pages/settings/users/UserDeleteForm.js +++ b/components/pages/settings/users/UserDeleteForm.js @@ -1,7 +1,7 @@ import { useMutation } from '@tanstack/react-query'; import useApi from 'hooks/useApi'; import { Button, Form, FormButtons, SubmitButton } from 'react-basics'; -import { useIntl } from 'react-intl'; +import { useIntl, FormattedMessage } from 'react-intl'; import { labels, messages } from 'components/messages'; export default function UserDeleteForm({ userId, username, onSave, onClose }) { @@ -20,9 +20,14 @@ export default function UserDeleteForm({ userId, username, onSave, onClose }) { return ( -

{formatMessage(messages.deleteUserWarning, { username })}

+

+ {username} }} + /> +

- + {formatMessage(labels.delete)} @@ -68,18 +66,20 @@ export default function UsersTable({ data = [], onDelete }) { - {close => ( - - )} + + {close => ( + + )} + ), diff --git a/components/pages/settings/websites/WebsiteAddForm.js b/components/pages/settings/websites/WebsiteAddForm.js index 40128f7a..8a864549 100644 --- a/components/pages/settings/websites/WebsiteAddForm.js +++ b/components/pages/settings/websites/WebsiteAddForm.js @@ -25,6 +25,7 @@ export default function WebsiteAddForm({ onSave, onClose }) { mutate(data, { onSuccess: async () => { onSave(); + onClose(); }, }); }; diff --git a/components/pages/settings/websites/WebsiteDeleteForm.js b/components/pages/settings/websites/WebsiteDeleteForm.js index 7a173525..c1ec10e0 100644 --- a/components/pages/settings/websites/WebsiteDeleteForm.js +++ b/components/pages/settings/websites/WebsiteDeleteForm.js @@ -22,6 +22,7 @@ export default function WebsiteDeleteForm({ websiteId, onSave, onClose }) { mutate(data, { onSuccess: async () => { onSave(); + onClose(); }, }); }; diff --git a/components/pages/settings/websites/WebsiteReset.js b/components/pages/settings/websites/WebsiteReset.js index 9c20627c..d742d113 100644 --- a/components/pages/settings/websites/WebsiteReset.js +++ b/components/pages/settings/websites/WebsiteReset.js @@ -1,6 +1,4 @@ -import { useRouter } from 'next/router'; -import { useState } from 'react'; -import { Button, Form, FormRow, Modal } from 'react-basics'; +import { Button, Form, FormRow, Modal, ModalTrigger } from 'react-basics'; import { useIntl } from 'react-intl'; import WebsiteDeleteForm from 'components/pages/settings/websites/WebsiteDeleteForm'; import WebsiteResetForm from 'components/pages/settings/websites/WebsiteResetForm'; @@ -8,43 +6,39 @@ import { labels, messages } from 'components/messages'; export default function WebsiteReset({ websiteId, onSave }) { const { formatMessage } = useIntl(); - const [modal, setModal] = useState(null); - const router = useRouter(); const handleReset = async () => { - setModal(null); - onSave(); + onSave('reset'); }; const handleDelete = async () => { - onSave(); - await router.push('/websites'); + onSave('delete'); }; - const handleClose = () => setModal(null); - return (

{formatMessage(messages.resetWebsiteWarning)}

- + + + + {close => ( + + )} + +

{formatMessage(messages.deleteWebsiteWarning)}

- + + + + {close => ( + + )} + +
- {modal === 'reset' && ( - - {close => } - - )} - {modal === 'delete' && ( - - {close => ( - - )} - - )} ); } diff --git a/components/pages/settings/websites/WebsiteResetForm.js b/components/pages/settings/websites/WebsiteResetForm.js index 68ebdea9..b88de986 100644 --- a/components/pages/settings/websites/WebsiteResetForm.js +++ b/components/pages/settings/websites/WebsiteResetForm.js @@ -22,6 +22,7 @@ export default function WebsiteResetForm({ websiteId, onSave, onClose }) { mutate(data, { onSuccess: async () => { onSave(); + onClose(); }, }); }; diff --git a/components/pages/settings/websites/WebsiteSettings.js b/components/pages/settings/websites/WebsiteSettings.js index c6ad4bcd..a6ee5092 100644 --- a/components/pages/settings/websites/WebsiteSettings.js +++ b/components/pages/settings/websites/WebsiteSettings.js @@ -1,6 +1,7 @@ import { useEffect, useState } from 'react'; import { Breadcrumbs, Item, Tabs, useToast, Button, Text, Icon, Icons } from 'react-basics'; import { useIntl } from 'react-intl'; +import { useRouter } from 'next/router'; import Link from 'next/link'; import Page from 'components/layout/Page'; import PageHeader from 'components/layout/PageHeader'; @@ -11,9 +12,8 @@ import ShareUrl from 'components/pages/settings/websites/ShareUrl'; import useApi from 'hooks/useApi'; import { labels, messages } from 'components/messages'; -const { External } = Icons; - export default function WebsiteSettings({ websiteId }) { + const router = useRouter(); const { formatMessage } = useIntl(); const [values, setValues] = useState(null); const [tab, setTab] = useState('details'); @@ -34,6 +34,12 @@ export default function WebsiteSettings({ websiteId }) { setValues(state => ({ ...state, ...data })); }; + const handleReset = async value => { + if (value === 'delete') { + await router.push('/websites'); + } + }; + useEffect(() => { if (data) { setValues(data); @@ -54,7 +60,7 @@ export default function WebsiteSettings({ websiteId }) {
@@ -72,7 +78,7 @@ export default function WebsiteSettings({ websiteId }) { )} {tab === 'tracking' && } {tab === 'share' && } - {tab === 'data' && } + {tab === 'data' && } ); } diff --git a/components/pages/settings/websites/WebsitesList.js b/components/pages/settings/websites/WebsitesList.js index 52908b47..7c70d895 100644 --- a/components/pages/settings/websites/WebsitesList.js +++ b/components/pages/settings/websites/WebsitesList.js @@ -1,5 +1,4 @@ -import { useState } from 'react'; -import { Button, Icon, Text, Modal, useToast, Icons } from 'react-basics'; +import { Button, Icon, Text, Modal, ModalTrigger, useToast, Icons } from 'react-basics'; import { useIntl } from 'react-intl'; import Page from 'components/layout/Page'; import PageHeader from 'components/layout/PageHeader'; @@ -10,10 +9,7 @@ import useApi from 'hooks/useApi'; import useUser from 'hooks/useUser'; import { labels, messages } from 'components/messages'; -const { Plus } = Icons; - export default function WebsitesList() { - const [edit, setEdit] = useState(false); const { user } = useUser(); const { get, useQuery } = useApi(); const { data, isLoading, error, refetch } = useQuery( @@ -27,21 +23,21 @@ export default function WebsitesList() { const handleSave = async () => { await refetch(); - setEdit(false); showToast({ message: formatMessage(messages.saved), variant: 'success' }); }; - const handleAdd = () => setEdit(true); - - const handleClose = () => setEdit(false); - const addButton = ( - + + + + {close => } + + ); return ( @@ -54,11 +50,6 @@ export default function WebsitesList() { {addButton} )} - {edit && ( - - {close => } - - )} ); } diff --git a/components/pages/settings/websites/WebsitesTable.js b/components/pages/settings/websites/WebsitesTable.js index 251b9d7e..5c38782d 100644 --- a/components/pages/settings/websites/WebsitesTable.js +++ b/components/pages/settings/websites/WebsitesTable.js @@ -13,8 +13,6 @@ import { } from 'react-basics'; import { defineMessages, useIntl } from 'react-intl'; -const { ArrowRight, External } = Icons; - const messages = defineMessages({ name: { id: 'label.name', defaultMessage: 'Name' }, domain: { id: 'label.domain', defaultMessage: 'Domain' }, @@ -50,7 +48,7 @@ export default function WebsitesTable({ data = [] }) { @@ -60,7 +58,7 @@ export default function WebsitesTable({ data = [] }) { diff --git a/components/pages/websites/WebsiteChartList.js b/components/pages/websites/WebsiteChartList.js index 262e694b..d0545dcc 100644 --- a/components/pages/websites/WebsiteChartList.js +++ b/components/pages/websites/WebsiteChartList.js @@ -1,28 +1,11 @@ -import { defineMessages, useIntl } from 'react-intl'; -import Link from 'components/common/Link'; import WebsiteChart from 'components/metrics/WebsiteChart'; -import Page from 'components/layout/Page'; -import EmptyPlaceholder from 'components/common/EmptyPlaceholder'; -import Arrow from 'assets/arrow-right.svg'; import styles from './WebsiteList.module.css'; import useDashboard from 'store/dashboard'; import { useMemo } from 'react'; import { firstBy } from 'thenby'; -const messages = defineMessages({ - noWebsites: { - id: 'message.no-websites-configured', - defaultMessage: "You don't have any websites configured.", - }, - goToSettngs: { - id: 'message.go-to-buttons', - defaultMessage: 'Go to buttons', - }, -}); - export default function WebsiteList({ websites, showCharts, limit }) { const { websiteOrder } = useDashboard(); - const { formatMessage } = useIntl(); const ordered = useMemo( () => @@ -32,18 +15,6 @@ export default function WebsiteList({ websites, showCharts, limit }) { [websites, websiteOrder], ); - if (websites.length === 0) { - return ( - - - } iconRight> - {formatMessage(messages.goToSettngs)} - - - - ); - } - return (
{ordered.map(({ id, name, domain }, index) => diff --git a/package.json b/package.json index 1846eb9d..bec13668 100644 --- a/package.json +++ b/package.json @@ -94,7 +94,7 @@ "npm-run-all": "^4.1.5", "prop-types": "^15.7.2", "react": "^18.2.0", - "react-basics": "^0.62.0", + "react-basics": "^0.63.0", "react-beautiful-dnd": "^13.1.0", "react-dom": "^18.2.0", "react-intl": "^5.24.7", @@ -103,7 +103,7 @@ "react-tooltip": "^4.2.21", "react-use-measure": "^2.0.4", "react-window": "^1.8.6", - "redis": "^4.5.0", + "redis": "^4.6.2", "request-ip": "^3.3.0", "semver": "^7.3.6", "thenby": "^1.3.4", diff --git a/yarn.lock b/yarn.lock index efdba584..3463bcf7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1627,9 +1627,9 @@ unstorage "^1.0.0" "@netlify/plugin-nextjs@^4.27.3": - version "4.30.0" - resolved "https://registry.yarnpkg.com/@netlify/plugin-nextjs/-/plugin-nextjs-4.30.0.tgz#1e4330ff1094057fc337d3b3504cf4a87b1cdbab" - integrity sha512-+MyfV6biKGVs/jQQUKGi2vN5aFFyRUTeEAItDiSvNhAUi0mOXEkEmu5JN7ZAQtL2oRIKKnxflsZDmtP3DdAahg== + version "4.30.2" + resolved "https://registry.yarnpkg.com/@netlify/plugin-nextjs/-/plugin-nextjs-4.30.2.tgz#c783ecb0eb080a1f124fc331360c6403378fca68" + integrity sha512-hqvdHlQEMfpTXh+fM0jwvtKla/gUS4gVKEZeQEkJlCzAJO+8XT2bTFAGrusNHLQ53L081nLXVXx1c+HUo0LFfQ== dependencies: "@netlify/esbuild" "0.14.39" "@netlify/functions" "^1.4.0" @@ -1946,6 +1946,11 @@ resolved "https://registry.yarnpkg.com/@redis/bloom/-/bloom-1.1.0.tgz#64e310ddee72010676e14296076329e594a1f6c7" integrity sha512-9QovlxmpRtvxVbN0UBcv8WfdSMudNZZTFqCsnBszcQXqaZb/TVe30ScgGEO7u1EAIacTPAo7/oCYjYAxiHLanQ== +"@redis/bloom@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@redis/bloom/-/bloom-1.2.0.tgz#d3fd6d3c0af3ef92f26767b56414a370c7b63b71" + integrity sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg== + "@redis/client@1.4.2": version "1.4.2" resolved "https://registry.yarnpkg.com/@redis/client/-/client-1.4.2.tgz#2a3f5e98bc33b7b979390442e6e08f96e57fabdd" @@ -1955,6 +1960,15 @@ generic-pool "3.9.0" yallist "4.0.0" +"@redis/client@1.5.3": + version "1.5.3" + resolved "https://registry.yarnpkg.com/@redis/client/-/client-1.5.3.tgz#2295ca770c9c40dcc59a96da9d05f4403c32e847" + integrity sha512-kPad3QmWyRcmFj1gnb+SkzjXBV7oPpyTJmasVA+ocgNClxqZaTJjLFReqxm9cZQiCtqZK9vrcTISNrgzQXFpLg== + dependencies: + cluster-key-slot "1.1.2" + generic-pool "3.9.0" + yallist "4.0.0" + "@redis/graph@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@redis/graph/-/graph-1.1.0.tgz#cc2b82e5141a29ada2cce7d267a6b74baa6dd519" @@ -1970,6 +1984,11 @@ resolved "https://registry.yarnpkg.com/@redis/search/-/search-1.1.0.tgz#7abb18d431f27ceafe6bcb4dd83a3fa67e9ab4df" integrity sha512-NyFZEVnxIJEybpy+YskjgOJRNsfTYqaPbK/Buv6W2kmFNaRk85JiqjJZA5QkRmWvGbyQYwoO5QfDi2wHskKrQQ== +"@redis/search@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@redis/search/-/search-1.1.1.tgz#f547b76b74f267831d3b368e3d7bba3a6a9e32bd" + integrity sha512-pqCXTc5e7wJJgUuJiC3hBgfoFRoPxYzwn0BEfKgejTM7M/9zP3IpUcqcjgfp8hF+LoV8rHZzcNTz7V+pEIY7LQ== + "@redis/time-series@1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@redis/time-series/-/time-series-1.0.4.tgz#af85eb080f6934580e4d3b58046026b6c2b18717" @@ -2119,17 +2138,17 @@ dependencies: tslib "^2.4.0" -"@tanstack/query-core@4.22.0": - version "4.22.0" - resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-4.22.0.tgz#7a786fcea64e229ed5d4308093dd644cdfaa895e" - integrity sha512-OeLyBKBQoT265f5G9biReijeP8mBxNFwY7ZUu1dKL+YzqpG5q5z7J/N1eT8aWyKuhyDTiUHuKm5l+oIVzbtrjw== +"@tanstack/query-core@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-4.22.4.tgz#aca622d2f8800a147ece5520d956a076ab92f0ea" + integrity sha512-t79CMwlbBnj+yL82tEcmRN93bL4U3pae2ota4t5NN2z3cIeWw74pzdWrKRwOfTvLcd+b30tC+ciDlfYOKFPGUw== "@tanstack/react-query@^4.16.1": - version "4.22.0" - resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-4.22.0.tgz#aaa4b41a6d306be6958018c74a8a3bb3e9f1924c" - integrity sha512-P9o+HjG42uB/xHR6dMsJaPhtZydSe4v0xdG5G/cEj1oHZAXelMlm67/rYJNQGKgBamKElKogj+HYGF+NY2yHYg== + version "4.23.0" + resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-4.23.0.tgz#0b9e14269a48cf5a4ffe46c8525cdb9df2ebd9cf" + integrity sha512-cfQsrecZQjYYueiow4WcK8ItokXJnv+b2OrK8Lf5kF7lM9uCo1ilyygFB8wo4MfxchUBVM6Cs8wq4Ed7fouwkA== dependencies: - "@tanstack/query-core" "4.22.0" + "@tanstack/query-core" "4.22.4" use-sync-external-store "^1.2.0" "@trysound/sax@0.2.0": @@ -3050,7 +3069,7 @@ cluster-key-slot@1.1.1: resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.1.tgz#10ccb9ded0729464b6d2e7d714b100a2d1259d43" integrity sha512-rwHwUfXL40Chm1r08yrhU3qpUvdVlgkKNeyeGPOxnW8/SyVDvgRaed/Uz54AqWNaTCAThlj6QAs3TZcKI0xDEw== -cluster-key-slot@^1.1.0: +cluster-key-slot@1.1.2, cluster-key-slot@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac" integrity sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA== @@ -3417,7 +3436,7 @@ date-fns-tz@^1.1.4: resolved "https://registry.yarnpkg.com/date-fns-tz/-/date-fns-tz-1.3.7.tgz#e8e9d2aaceba5f1cc0e677631563081fdcb0e69a" integrity sha512-1t1b8zyJo+UI8aR+g3iqr5fkUHWpd58VBx8J/ZSQ+w7YrGlw80Ag4sA86qkfCXRBLmMc4I2US+aPMd4uKvwj5g== -date-fns@^2.23.0: +date-fns@^2.23.0, date-fns@^2.29.3: version "2.29.3" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.3.tgz#27402d2fc67eb442b511b70bbdf98e6411cd68a8" integrity sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA== @@ -3501,10 +3520,10 @@ define-properties@^1.1.3, define-properties@^1.1.4: has-property-descriptors "^1.0.0" object-keys "^1.1.1" -defu@^6.0.0, defu@^6.1.0, defu@^6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/defu/-/defu-6.1.1.tgz#a12c712349197c545dc61d3cd3b607b4cc7ef0c1" - integrity sha512-aA964RUCsBt0FGoNIlA3uFgo2hO+WWC0fiC6DBps/0SFzkKcYoM/3CzVLIa5xSsrFjdioMdYgAIbwo80qp2MoA== +defu@^6.0.0, defu@^6.1.0, defu@^6.1.2: + version "6.1.2" + resolved "https://registry.yarnpkg.com/defu/-/defu-6.1.2.tgz#1217cba167410a1765ba93893c6dbac9ed9d9e5c" + integrity sha512-+uO4+qr7msjNNWKYPHqN/3+Dx3NFkmIzayk2L1MyZQlvgZb/J1A0fo410dpKrN2SnqFjt8n4JL8fDJE0wIgjFQ== del@^6.0.0: version "6.1.1" @@ -3525,7 +3544,7 @@ delayed-stream@~1.0.0: resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== -denque@^2.0.1: +denque@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/denque/-/denque-2.1.0.tgz#e93e1a6569fb5e66f16a3c2a2964617d349d6ab1" integrity sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw== @@ -4360,6 +4379,11 @@ get-port-please@^2.6.1: dependencies: fs-memo "^1.2.0" +get-port-please@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/get-port-please/-/get-port-please-3.0.1.tgz#a24953a41dc249f76869ac25e81d6623e61ab010" + integrity sha512-R5pcVO8Z1+pVDu8Ml3xaJCEkBiiy1VQN9za0YqH8GIi1nIqD4IzQhzY6dDzMRtdS1lyiGlucRzm8IN8wtLIXng== + get-stream@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" @@ -4496,9 +4520,9 @@ graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== h3@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/h3/-/h3-1.0.2.tgz#3a2992921a62de697bd4a3f449401f7600116df6" - integrity sha512-25QqjQMz8pX1NI2rZ/ziNT9B8Aog7jmu2a0o8Qm9kKoH3zOhE+2icVs069h6DEp0g1Dst1+zKfRdRYcK0MogJA== + version "1.1.0" + resolved "https://registry.yarnpkg.com/h3/-/h3-1.1.0.tgz#ff10d590005711dfb41034b9b1496d165507b1ea" + integrity sha512-kx3u+RMzY963fU8NNT2ePWgsryAn9DNztPqbHia/M7HgA+rtXKjHjED9/uidcYPmImNwAfJsCachCzh2T3QH2A== dependencies: cookie-es "^0.5.0" destr "^1.2.2" @@ -4638,9 +4662,9 @@ image-meta@^0.1.1: integrity sha512-+oXiHwOEPr1IE5zY0tcBLED/CYcre15J4nwL50x3o0jxWqEkyjrusiKP3YSU+tr9fvJp33ZcP5Gpj2295g3aEw== immer@^9.0.12: - version "9.0.18" - resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.18.tgz#d2faee58fd0e34f017f329b98cdab37826fa31b8" - integrity sha512-eAPNpsj7Ax1q6Y/3lm2PmlwRcFzpON7HSNQ3ru5WQH1/PSpnyed/HpNOELl2CxLKoj4r+bAHgdyKqW5gc2Se1A== + version "9.0.19" + resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.19.tgz#67fb97310555690b5f9cd8380d38fc0aabb6b38b" + integrity sha512-eY+Y0qcsB4TZKwgQzLaE/lqYMlKhv5J9dyd2RhhtGhNo2njPXDqU9XPfcNfa3MIDsdtZt5KlkIsirlo4dHsWdQ== import-fresh@^3.0.0, import-fresh@^3.2.1: version "3.3.0" @@ -4723,14 +4747,14 @@ intl-messageformat@9.13.0: tslib "^2.1.0" ioredis@^5.2.4: - version "5.2.5" - resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-5.2.5.tgz#c62dc3945ad2a8f0323fbb2765b934a84a68cde0" - integrity sha512-7HKo/ClM2DGLRXdFq8ruS3Uuadensz4A76wPOU0adqlOqd1qkhoLPDaBhmVhUhNGpB+J65/bhLmNB8DDY99HJQ== + version "5.3.0" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-5.3.0.tgz#b5469f0fd374648ef074840c00c1d8eed42fca3f" + integrity sha512-Id9jKHhsILuIZpHc61QkagfVdUj2Rag5GzG1TGEvRNeM7dtTOjICgjC+tvqYxi//PuX2wjQ+Xjva2ONBuf92Pw== dependencies: "@ioredis/commands" "^1.1.1" cluster-key-slot "^1.1.0" debug "^4.3.4" - denque "^2.0.1" + denque "^2.1.0" lodash.defaults "^4.2.0" lodash.isarguments "^3.1.0" redis-errors "^1.2.0" @@ -5239,18 +5263,18 @@ listhen@^0.2.15: ufo "^0.8.5" listhen@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/listhen/-/listhen-1.0.1.tgz#31054d08d850ad21473768085a50a8b34a635070" - integrity sha512-RBzBGHMCc5wP8J5Vf8WgF4CAJH8dWHi9LaKB7vfzZt54CiH/0dp01rudy2hFD9wCrTM+UfxFVnn5wTIiY+Qhiw== + version "1.0.2" + resolved "https://registry.yarnpkg.com/listhen/-/listhen-1.0.2.tgz#3332af0cf77dd914e12d125c70a9c6aed9537033" + integrity sha512-yXz0NIYfVJDBQK2vlCpD/OjSzYkur2mR44boUtlg0eES4holn7oYZf439y5JxP55EOzFtClZ8eZlMJ8a++FwlQ== dependencies: clipboardy "^3.0.0" colorette "^2.0.19" - defu "^6.1.1" - get-port-please "^2.6.1" + defu "^6.1.2" + get-port-please "^3.0.1" http-shutdown "^1.2.2" ip-regex "^5.0.0" node-forge "^1.3.1" - ufo "^1.0.0" + ufo "^1.0.1" listr2@^3.12.2: version "3.14.0" @@ -6562,12 +6586,13 @@ rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-basics@^0.62.0: - version "0.62.0" - resolved "https://registry.yarnpkg.com/react-basics/-/react-basics-0.62.0.tgz#7d4890632d9a0086e54f7472b9e59db0c973dd86" - integrity sha512-/m9LXHwRCX3uqT8exJp+D0PsDqQBAfg4BXpqRuXmQBMmEYjixQo+qBLHcbnJ0/6qLrsyb/5y4VBrorWQ2HtKiQ== +react-basics@^0.63.0: + version "0.63.0" + resolved "https://registry.yarnpkg.com/react-basics/-/react-basics-0.63.0.tgz#1b203c701f6936076633994ed8175234bde93694" + integrity sha512-G6+1Z921kC/TyjZCABrDlNeB22YkN6q7V70xREGSiO55OXU73MLT+Kk96GDWYfKa5lB1zI5rCbbvGz3ELuU+mA== dependencies: classnames "^2.3.1" + date-fns "^2.29.3" react "^18.2.0" react-dom "^18.2.0" react-hook-form "^7.34.2" @@ -6786,7 +6811,7 @@ redis-parser@^3.0.0: dependencies: redis-errors "^1.0.0" -redis@^4.5.0, redis@^4.5.1: +redis@^4.5.1: version "4.5.1" resolved "https://registry.yarnpkg.com/redis/-/redis-4.5.1.tgz#f5a818970bb2dc5d60540bab41308640604c7d33" integrity sha512-oxXSoIqMJCQVBTfxP6BNTCtDMyh9G6Vi5wjdPdV/sRKkufyZslDqCScSGcOr6XGR/reAWZefz7E4leM31RgdBA== @@ -6798,6 +6823,18 @@ redis@^4.5.0, redis@^4.5.1: "@redis/search" "1.1.0" "@redis/time-series" "1.0.4" +redis@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/redis/-/redis-4.6.2.tgz#5592db7b95c1b6652cde463e58a8029a1f7890bb" + integrity sha512-Xoh7UyU6YnT458xA8svaZAJu6ZunKeW7Z/7GXrLWGGwhVLTsDX6pr3u7ENAoV+DHBPO+9LwIu45ClwUwpIjAxw== + dependencies: + "@redis/bloom" "1.2.0" + "@redis/client" "1.5.3" + "@redis/graph" "1.1.0" + "@redis/json" "1.0.4" + "@redis/search" "1.1.1" + "@redis/time-series" "1.0.4" + redux@^4.0.0, redux@^4.0.4: version "4.2.0" resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.0.tgz#46f10d6e29b6666df758780437651eeb2b969f13" @@ -7867,9 +7904,9 @@ unbox-primitive@^1.0.2: which-boxed-primitive "^1.0.2" undici@^5.12.0: - version "5.15.1" - resolved "https://registry.yarnpkg.com/undici/-/undici-5.15.1.tgz#5292454b1441da486a80c0f3ada1e88f1765ff8d" - integrity sha512-XLk8g0WAngdvFqTI+VKfBtM4YWXgdxkf1WezC771Es0Dd+Pm1KmNx8t93WTC+Hh9tnghmVxkclU1HN+j+CvIUA== + version "5.16.0" + resolved "https://registry.yarnpkg.com/undici/-/undici-5.16.0.tgz#6b64f9b890de85489ac6332bd45ca67e4f7d9943" + integrity sha512-KWBOXNv6VX+oJQhchXieUznEmnJMqgXMbs0xxH2t8q/FUAWSJvOSr/rMaZKnX5RIVq7JDn0JbP4BOnKG2SGXLQ== dependencies: busboy "^1.6.0"