diff --git a/.eslintrc.json b/.eslintrc.json index 25e83d5a..a77ed5bd 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -19,22 +19,21 @@ "plugin:@typescript-eslint/recommended", "next" ], - "plugins": ["@typescript-eslint", "prettier"], "settings": { "import/resolver": { "alias": { "map": [ - ["assets", "./assets"], - ["components", "./components"], + ["assets", "./src/assets"], + ["components", "./src/components"], ["db", "./db"], - ["hooks", "./hooks"], - ["lang", "./lang"], - ["lib", "./lib"], + ["hooks", "./src/components/hooks"], + ["lang", "./src/lang"], + ["lib", "./src/lib"], ["public", "./public"], - ["queries", "./queries"], - ["store", "./store"], - ["styles", "./styles"] + ["queries", "./src/queries"], + ["store", "./src/store"], + ["styles", "./src/styles"] ], "extensions": [".ts", ".tsx", ".js", ".jsx", ".json"] } @@ -51,7 +50,8 @@ "@typescript-eslint/no-empty-function": "off", "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-var-requires": "off", - "@typescript-eslint/no-empty-interface": "off" + "@typescript-eslint/no-empty-interface": "off", + "@typescript-eslint/no-unused-vars": ["error", { "ignoreRestSiblings": true }] }, "globals": { "React": "writable" diff --git a/components/input/WebsiteDateFilter.js b/components/input/WebsiteDateFilter.js deleted file mode 100644 index 47e6f016..00000000 --- a/components/input/WebsiteDateFilter.js +++ /dev/null @@ -1,23 +0,0 @@ -import useDateRange from 'hooks/useDateRange'; -import DateFilter from './DateFilter'; -import styles from './WebsiteDateFilter.module.css'; - -export default function WebsiteDateFilter({ websiteId }) { - const [dateRange, setDateRange] = useDateRange(websiteId); - const { value, startDate, endDate } = dateRange; - - const handleChange = async value => { - setDateRange(value); - }; - - return ( - - ); -} diff --git a/components/pages/settings/users/UserWebsites.js b/components/pages/settings/users/UserWebsites.js deleted file mode 100644 index 144fae44..00000000 --- a/components/pages/settings/users/UserWebsites.js +++ /dev/null @@ -1,26 +0,0 @@ -import { Loading } from 'react-basics'; -import useApi from 'hooks/useApi'; -import WebsitesTable from 'components/pages/settings/websites/WebsitesTable'; -import useMessages from 'hooks/useMessages'; - -export function UserWebsites({ userId }) { - const { formatMessage, messages } = useMessages(); - const { get, useQuery } = useApi(); - const { data, isLoading } = useQuery(['user:websites', userId], () => - get(`/users/${userId}/websites`), - ); - const hasData = data && data.length !== 0; - - if (isLoading) { - return ; - } - - return ( -
- {hasData && } - {!hasData && formatMessage(messages.noDataAvailable)} -
- ); -} - -export default UserWebsites; diff --git a/jsconfig.json b/jsconfig.json index b639b0f8..738e8a46 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -1,5 +1,5 @@ { "compilerOptions": { - "baseUrl": "." + "baseUrl": "./src" } -} \ No newline at end of file +} diff --git a/next.config.js b/next.config.js index 2165a6e0..4ab77510 100644 --- a/next.config.js +++ b/next.config.js @@ -1,5 +1,6 @@ /* eslint-disable @typescript-eslint/no-var-requires */ require('dotenv').config(); +const path = require('path'); const pkg = require('./package.json'); const contentSecurityPolicy = ` @@ -92,6 +93,8 @@ const config = { use: ['@svgr/webpack'], }); + config.resolve.alias['public'] = path.resolve('./public'); + return config; }, async headers() { diff --git a/package.components.json b/package.components.json new file mode 100644 index 00000000..feb3fc2e --- /dev/null +++ b/package.components.json @@ -0,0 +1,23 @@ +{ + "name": "@umami/components", + "version": "0.11.0", + "description": "Umami React components.", + "author": "Mike Cao ", + "license": "MIT", + "type": "module", + "main": "./index.js", + "types": "./index.d.ts", + "peerDependencies": { + "@tanstack/react-query": "^4.33.0", + "classnames": "^2.3.1", + "colord": "^2.9.2", + "immer": "^9.0.12", + "moment-timezone": "^0.5.35", + "next": "^13.4.0", + "next-basics": "^0.36.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-intl": "^5.24.7", + "zustand": "^4.3.8" + } +} diff --git a/package.json b/package.json index e1361d20..1ff1730d 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,8 @@ "start-env": "node scripts/start-env.js", "start-server": "node server.js", "build-app": "next build", - "build-tracker": "rollup -c rollup.tracker.config.js", + "build-components": "rollup -c rollup.components.config.mjs", + "build-tracker": "rollup -c rollup.tracker.config.mjs", "build-db": "npm-run-all copy-db-files build-db-client", "build-lang": "npm-run-all format-lang compile-lang download-country-names download-language-names", "build-geo": "node scripts/build-geo.js", @@ -61,7 +62,7 @@ "dependencies": { "@fontsource/inter": "^4.5.15", "@prisma/client": "5.0.0", - "@tanstack/react-query": "^4.16.1", + "@tanstack/react-query": "^4.33.0", "@umami/prisma-client": "^0.2.0", "@umami/redis-client": "^0.5.0", "chalk": "^4.1.1", @@ -89,7 +90,7 @@ "kafkajs": "^2.1.0", "maxmind": "^4.3.6", "moment-timezone": "^0.5.35", - "next": "13.3.1", + "next": "13.4.19", "next-basics": "^0.36.0", "node-fetch": "^3.2.8", "npm-run-all": "^4.1.5", @@ -115,13 +116,16 @@ "@formatjs/cli": "^4.2.29", "@netlify/plugin-nextjs": "^4.27.3", "@rollup/plugin-alias": "^5.0.0", - "@rollup/plugin-buble": "^0.21.3", - "@rollup/plugin-commonjs": "^24.1.0", + "@rollup/plugin-buble": "^1.0.2", + "@rollup/plugin-commonjs": "^25.0.4", "@rollup/plugin-json": "^6.0.0", - "@rollup/plugin-node-resolve": "^15.0.2", - "@rollup/plugin-replace": "^4.0.0", - "@svgr/rollup": "^7.0.0", + "@rollup/plugin-node-resolve": "^15.2.0", + "@rollup/plugin-replace": "^5.0.2", + "@svgr/rollup": "^8.1.0", "@svgr/webpack": "^6.2.1", + "@types/node": "^18.11.9", + "@types/react": "^18.0.25", + "@types/react-dom": "^18.0.8", "@typescript-eslint/eslint-plugin": "^5.50.0", "@typescript-eslint/parser": "^5.50.0", "cross-env": "^7.0.3", @@ -143,11 +147,12 @@ "prettier": "^2.6.2", "prisma": "5.0.0", "prompts": "2.4.2", - "rollup": "^2.70.1", + "rollup": "^3.28.0", + "rollup-plugin-copy": "^3.4.0", "rollup-plugin-delete": "^2.0.0", - "rollup-plugin-dts": "^5.3.0", + "rollup-plugin-dts": "^5.3.1", "rollup-plugin-esbuild": "^5.0.0", - "rollup-plugin-node-externals": "^5.1.2", + "rollup-plugin-node-externals": "^6.1.1", "rollup-plugin-postcss": "^4.0.2", "rollup-plugin-terser": "^7.0.2", "stylelint": "^15.10.1", @@ -156,6 +161,6 @@ "stylelint-config-recommended": "^9.0.0", "tar": "^6.1.2", "ts-node": "^10.9.1", - "typescript": "^4.9.5" + "typescript": "^5.1.6" } } diff --git a/pages/api/reports/insights.ts b/pages/api/reports/insights.ts deleted file mode 100644 index 09a07d2f..00000000 --- a/pages/api/reports/insights.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { canViewWebsite } from 'lib/auth'; -import { useCors, useAuth } from 'lib/middleware'; -import { NextApiRequestQueryBody } from 'lib/types'; -import { NextApiResponse } from 'next'; -import { ok, methodNotAllowed, unauthorized } from 'next-basics'; -import { getInsights } from 'queries'; - -export interface InsightsRequestBody { - websiteId: string; - dateRange: { - startDate: string; - endDate: string; - }; - fields: { name: string; type: string; value: string }[]; - filters: string[]; - groups: { name: string; type: string }[]; -} - -function convertFilters(filters) { - return filters.reduce((obj, { name, ...value }) => { - obj[name] = value; - - return obj; - }, {}); -} - -export default async ( - req: NextApiRequestQueryBody, - res: NextApiResponse, -) => { - await useCors(req, res); - await useAuth(req, res); - - if (req.method === 'POST') { - const { - websiteId, - dateRange: { startDate, endDate }, - fields, - filters, - } = req.body; - - if (!(await canViewWebsite(req.auth, websiteId))) { - return unauthorized(res); - } - - const data = await getInsights(websiteId, fields, { - ...convertFilters(filters), - startDate: new Date(startDate), - endDate: new Date(endDate), - }); - - return ok(res, data); - } - - return methodNotAllowed(res); -}; diff --git a/rollup.components.config.mjs b/rollup.components.config.mjs new file mode 100644 index 00000000..a0b8efbd --- /dev/null +++ b/rollup.components.config.mjs @@ -0,0 +1,94 @@ +import path from 'path'; +import crypto from 'crypto'; +import resolve from '@rollup/plugin-node-resolve'; +import alias from '@rollup/plugin-alias'; +import json from '@rollup/plugin-json'; +import postcss from 'rollup-plugin-postcss'; +import copy from 'rollup-plugin-copy'; +import del from 'rollup-plugin-delete'; +import nodeExternals from 'rollup-plugin-node-externals'; +import esbuild from 'rollup-plugin-esbuild'; +import dts from 'rollup-plugin-dts'; +import svgr from '@svgr/rollup'; + +const md5 = str => crypto.createHash('md5').update(str).digest('hex'); + +const customResolver = resolve({ + extensions: ['.js', '.jsx', '.ts', '.tsx'], +}); + +const aliasConfig = { + entries: [ + { find: /^components/, replacement: path.resolve('./src/components') }, + { find: /^hooks/, replacement: path.resolve('./src/hooks') }, + { find: /^lib/, replacement: path.resolve('./src/lib') }, + { find: /^store/, replacement: path.resolve('./src/store') }, + { find: /^public/, replacement: path.resolve('./public') }, + { find: /^assets/, replacement: path.resolve('./src/assets') }, + ], + customResolver, +}; + +const external = [ + 'react', + 'react-dom', + 'react/jsx-runtime', + 'react-intl', + 'react-basics', + 'classnames', + 'next', +]; + +const jsBundle = { + input: 'src/index.ts', + output: [ + { + file: 'dist/index.js', + format: 'es', + sourcemap: true, + }, + ], + plugins: [ + del({ targets: 'dist/*', runOnce: true }), + copy({ targets: [{ src: './package.components.json', dest: 'dist', rename: 'package.json' }] }), + postcss({ + config: false, + extract: 'styles.css', + sourceMap: true, + minimize: true, + modules: { + generateScopedName: function (name, filename, css) { + const file = path.basename(filename, '.css').replace('.module', ''); + const hash = Buffer.from(md5(`${name}:${filename}:${css}`)) + .toString('base64') + .substring(0, 5); + + return `${file}-${name}--${hash}`; + }, + }, + }), + svgr({ icon: true }), + nodeExternals(), + json(), + alias(aliasConfig), + esbuild({ + target: 'es6', + jsx: 'automatic', + loaders: { + '.js': 'jsx', + }, + }), + ], +}; + +const dtsBundle = { + input: 'src/index.ts', + output: { + file: 'dist/index.d.ts', + format: 'es', + }, + plugins: [alias(aliasConfig), nodeExternals(), json(), dts()], + external: [/\.css/], +}; + +export default [jsBundle, dtsBundle]; diff --git a/rollup.tracker.config.js b/rollup.tracker.config.mjs similarity index 93% rename from rollup.tracker.config.js rename to rollup.tracker.config.mjs index f4e7223c..465e1af3 100644 --- a/rollup.tracker.config.js +++ b/rollup.tracker.config.mjs @@ -4,7 +4,7 @@ import replace from '@rollup/plugin-replace'; import { terser } from 'rollup-plugin-terser'; export default { - input: 'tracker/index.js', + input: 'src/tracker/index.js', output: { file: 'public/script.js', format: 'iife', diff --git a/scripts/check-lang.js b/scripts/check-lang.js index e5a0bf09..a1b60431 100644 --- a/scripts/check-lang.js +++ b/scripts/check-lang.js @@ -2,7 +2,7 @@ const fs = require('fs'); const path = require('path'); const chalk = require('chalk'); -const messages = require('../lang/en-US.json'); +const messages = require('../src/lang/en-US.json'); const ignore = require('../lang-ignore.json'); const dir = path.resolve(__dirname, '../lang'); diff --git a/assets/add-user.svg b/src/assets/add-user.svg similarity index 100% rename from assets/add-user.svg rename to src/assets/add-user.svg diff --git a/assets/bar-chart.svg b/src/assets/bar-chart.svg similarity index 100% rename from assets/bar-chart.svg rename to src/assets/bar-chart.svg diff --git a/assets/bars.svg b/src/assets/bars.svg similarity index 100% rename from assets/bars.svg rename to src/assets/bars.svg diff --git a/assets/bolt.svg b/src/assets/bolt.svg similarity index 100% rename from assets/bolt.svg rename to src/assets/bolt.svg diff --git a/assets/calendar.svg b/src/assets/calendar.svg similarity index 100% rename from assets/calendar.svg rename to src/assets/calendar.svg diff --git a/assets/clock.svg b/src/assets/clock.svg similarity index 100% rename from assets/clock.svg rename to src/assets/clock.svg diff --git a/assets/dashboard.svg b/src/assets/dashboard.svg similarity index 100% rename from assets/dashboard.svg rename to src/assets/dashboard.svg diff --git a/assets/expand.svg b/src/assets/expand.svg similarity index 100% rename from assets/expand.svg rename to src/assets/expand.svg diff --git a/assets/eye.svg b/src/assets/eye.svg similarity index 100% rename from assets/eye.svg rename to src/assets/eye.svg diff --git a/assets/funnel.svg b/src/assets/funnel.svg similarity index 100% rename from assets/funnel.svg rename to src/assets/funnel.svg diff --git a/assets/gear.svg b/src/assets/gear.svg similarity index 100% rename from assets/gear.svg rename to src/assets/gear.svg diff --git a/assets/globe.svg b/src/assets/globe.svg similarity index 100% rename from assets/globe.svg rename to src/assets/globe.svg diff --git a/assets/lightbulb.svg b/src/assets/lightbulb.svg similarity index 100% rename from assets/lightbulb.svg rename to src/assets/lightbulb.svg diff --git a/assets/link.svg b/src/assets/link.svg similarity index 100% rename from assets/link.svg rename to src/assets/link.svg diff --git a/assets/lock.svg b/src/assets/lock.svg similarity index 100% rename from assets/lock.svg rename to src/assets/lock.svg diff --git a/assets/logo.svg b/src/assets/logo.svg similarity index 100% rename from assets/logo.svg rename to src/assets/logo.svg diff --git a/assets/magnet.svg b/src/assets/magnet.svg similarity index 100% rename from assets/magnet.svg rename to src/assets/magnet.svg diff --git a/assets/moon.svg b/src/assets/moon.svg similarity index 100% rename from assets/moon.svg rename to src/assets/moon.svg diff --git a/assets/nodes.svg b/src/assets/nodes.svg similarity index 100% rename from assets/nodes.svg rename to src/assets/nodes.svg diff --git a/assets/overview.svg b/src/assets/overview.svg similarity index 100% rename from assets/overview.svg rename to src/assets/overview.svg diff --git a/assets/profile.svg b/src/assets/profile.svg similarity index 100% rename from assets/profile.svg rename to src/assets/profile.svg diff --git a/assets/redo.svg b/src/assets/redo.svg similarity index 100% rename from assets/redo.svg rename to src/assets/redo.svg diff --git a/assets/reports.svg b/src/assets/reports.svg similarity index 100% rename from assets/reports.svg rename to src/assets/reports.svg diff --git a/assets/sun.svg b/src/assets/sun.svg similarity index 100% rename from assets/sun.svg rename to src/assets/sun.svg diff --git a/assets/user.svg b/src/assets/user.svg similarity index 100% rename from assets/user.svg rename to src/assets/user.svg diff --git a/assets/users.svg b/src/assets/users.svg similarity index 100% rename from assets/users.svg rename to src/assets/users.svg diff --git a/assets/visitor.svg b/src/assets/visitor.svg similarity index 100% rename from assets/visitor.svg rename to src/assets/visitor.svg diff --git a/assets/website.svg b/src/assets/website.svg similarity index 100% rename from assets/website.svg rename to src/assets/website.svg diff --git a/components/common/ConfirmDeleteForm.js b/src/components/common/ConfirmDeleteForm.js similarity index 84% rename from components/common/ConfirmDeleteForm.js rename to src/components/common/ConfirmDeleteForm.js index 3496a305..3d2c383d 100644 --- a/components/common/ConfirmDeleteForm.js +++ b/src/components/common/ConfirmDeleteForm.js @@ -1,6 +1,6 @@ import { useState } from 'react'; import { Button, LoadingButton, Form, FormButtons } from 'react-basics'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export function ConfirmDeleteForm({ name, onConfirm, onClose }) { const [loading, setLoading] = useState(false); @@ -17,7 +17,7 @@ export function ConfirmDeleteForm({ name, onConfirm, onClose }) { {name} }} />

- + {formatMessage(labels.delete)} diff --git a/components/common/Empty.js b/src/components/common/Empty.js similarity index 86% rename from components/common/Empty.js rename to src/components/common/Empty.js index 95681b16..c0be761a 100644 --- a/components/common/Empty.js +++ b/src/components/common/Empty.js @@ -1,6 +1,6 @@ import classNames from 'classnames'; import styles from './Empty.module.css'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export function Empty({ message, className }) { const { formatMessage, messages } = useMessages(); diff --git a/components/common/Empty.module.css b/src/components/common/Empty.module.css similarity index 100% rename from components/common/Empty.module.css rename to src/components/common/Empty.module.css diff --git a/components/common/EmptyPlaceholder.js b/src/components/common/EmptyPlaceholder.js similarity index 100% rename from components/common/EmptyPlaceholder.js rename to src/components/common/EmptyPlaceholder.js diff --git a/components/common/ErrorBoundary.js b/src/components/common/ErrorBoundary.js similarity index 93% rename from components/common/ErrorBoundary.js rename to src/components/common/ErrorBoundary.js index f97fd92c..32cedb39 100644 --- a/components/common/ErrorBoundary.js +++ b/src/components/common/ErrorBoundary.js @@ -1,7 +1,7 @@ /* eslint-disable no-console */ import { ErrorBoundary as Boundary } from 'react-error-boundary'; import { Button } from 'react-basics'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; import styles from './ErrorBoundry.module.css'; const logError = (error, info) => { diff --git a/components/common/ErrorBoundry.module.css b/src/components/common/ErrorBoundry.module.css similarity index 100% rename from components/common/ErrorBoundry.module.css rename to src/components/common/ErrorBoundry.module.css diff --git a/components/common/ErrorMessage.js b/src/components/common/ErrorMessage.js similarity index 88% rename from components/common/ErrorMessage.js rename to src/components/common/ErrorMessage.js index e2b22747..f8129c6b 100644 --- a/components/common/ErrorMessage.js +++ b/src/components/common/ErrorMessage.js @@ -1,6 +1,6 @@ import { Icon, Icons, Text } from 'react-basics'; import styles from './ErrorMessage.module.css'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export function ErrorMessage() { const { formatMessage, messages } = useMessages(); diff --git a/components/common/ErrorMessage.module.css b/src/components/common/ErrorMessage.module.css similarity index 100% rename from components/common/ErrorMessage.module.css rename to src/components/common/ErrorMessage.module.css diff --git a/components/common/Favicon.js b/src/components/common/Favicon.js similarity index 100% rename from components/common/Favicon.js rename to src/components/common/Favicon.js diff --git a/components/common/Favicon.module.css b/src/components/common/Favicon.module.css similarity index 100% rename from components/common/Favicon.module.css rename to src/components/common/Favicon.module.css diff --git a/components/common/FilterButtons.js b/src/components/common/FilterButtons.js similarity index 100% rename from components/common/FilterButtons.js rename to src/components/common/FilterButtons.js diff --git a/components/common/FilterLink.js b/src/components/common/FilterLink.js similarity index 91% rename from components/common/FilterLink.js rename to src/components/common/FilterLink.js index 30cdc025..2a95e011 100644 --- a/components/common/FilterLink.js +++ b/src/components/common/FilterLink.js @@ -2,8 +2,8 @@ import { Icon, Icons } from 'react-basics'; import classNames from 'classnames'; import Link from 'next/link'; import { safeDecodeURI } from 'next-basics'; -import usePageQuery from 'hooks/usePageQuery'; -import useMessages from 'hooks/useMessages'; +import usePageQuery from 'components/hooks/usePageQuery'; +import useMessages from 'components/hooks/useMessages'; import styles from './FilterLink.module.css'; export function FilterLink({ id, value, label, externalUrl, children, className }) { diff --git a/components/common/FilterLink.module.css b/src/components/common/FilterLink.module.css similarity index 100% rename from components/common/FilterLink.module.css rename to src/components/common/FilterLink.module.css diff --git a/components/common/HamburgerButton.js b/src/components/common/HamburgerButton.js similarity index 93% rename from components/common/HamburgerButton.js rename to src/components/common/HamburgerButton.js index 48c80770..9feee67b 100644 --- a/components/common/HamburgerButton.js +++ b/src/components/common/HamburgerButton.js @@ -2,8 +2,8 @@ import { Button, Icon } from 'react-basics'; import { useState } from 'react'; import MobileMenu from './MobileMenu'; import Icons from 'components/icons'; -import useMessages from 'hooks/useMessages'; -import useConfig from 'hooks/useConfig'; +import useMessages from 'components/hooks/useMessages'; +import useConfig from 'components/hooks/useConfig'; export function HamburgerButton() { const { formatMessage, labels } = useMessages(); diff --git a/components/common/HamburgerButton.module.css b/src/components/common/HamburgerButton.module.css similarity index 100% rename from components/common/HamburgerButton.module.css rename to src/components/common/HamburgerButton.module.css diff --git a/components/common/HoverTooltip.js b/src/components/common/HoverTooltip.js similarity index 100% rename from components/common/HoverTooltip.js rename to src/components/common/HoverTooltip.js diff --git a/components/common/HoverTooltip.module.css b/src/components/common/HoverTooltip.module.css similarity index 100% rename from components/common/HoverTooltip.module.css rename to src/components/common/HoverTooltip.module.css diff --git a/components/common/LinkButton.js b/src/components/common/LinkButton.js similarity index 77% rename from components/common/LinkButton.js rename to src/components/common/LinkButton.js index 8c050147..54c7fa63 100644 --- a/components/common/LinkButton.js +++ b/src/components/common/LinkButton.js @@ -2,7 +2,7 @@ import Link from 'next/link'; import { Icon, Icons, Text } from 'react-basics'; import styles from './LinkButton.module.css'; -export default function LinkButton({ href, icon, children }) { +export function LinkButton({ href, icon, children }) { return ( {icon || } @@ -10,3 +10,5 @@ export default function LinkButton({ href, icon, children }) { ); } + +export default LinkButton; diff --git a/components/common/LinkButton.module.css b/src/components/common/LinkButton.module.css similarity index 100% rename from components/common/LinkButton.module.css rename to src/components/common/LinkButton.module.css diff --git a/components/common/MobileMenu.js b/src/components/common/MobileMenu.js similarity index 100% rename from components/common/MobileMenu.js rename to src/components/common/MobileMenu.js diff --git a/components/common/MobileMenu.module.css b/src/components/common/MobileMenu.module.css similarity index 100% rename from components/common/MobileMenu.module.css rename to src/components/common/MobileMenu.module.css diff --git a/components/common/Pager.js b/src/components/common/Pager.js similarity index 95% rename from components/common/Pager.js rename to src/components/common/Pager.js index aaeffbae..7a5e7ed5 100644 --- a/components/common/Pager.js +++ b/src/components/common/Pager.js @@ -1,6 +1,6 @@ import styles from './Pager.module.css'; import { Button, Flexbox, Icon, Icons } from 'react-basics'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export function Pager({ page, pageSize, count, onPageChange }) { const { formatMessage, labels } = useMessages(); diff --git a/components/common/Pager.module.css b/src/components/common/Pager.module.css similarity index 100% rename from components/common/Pager.module.css rename to src/components/common/Pager.module.css diff --git a/components/common/SettingsTable.js b/src/components/common/SettingsTable.js similarity index 91% rename from components/common/SettingsTable.js rename to src/components/common/SettingsTable.js index e9491331..2df3b391 100644 --- a/components/common/SettingsTable.js +++ b/src/components/common/SettingsTable.js @@ -1,5 +1,5 @@ -import EmptyPlaceholder from 'components/common/EmptyPlaceholder'; -import useMessages from 'hooks/useMessages'; +import Empty from 'components/common/Empty'; +import useMessages from 'components/hooks/useMessages'; import { useState } from 'react'; import { SearchField, @@ -36,7 +36,7 @@ export function SettingsTable({ return ( <> - {showSearch && ( + {showSearch && !!value.length && ( )} {value.length === 0 && filterValue && ( - + )} {value.length > 0 && ( diff --git a/components/common/SettingsTable.module.css b/src/components/common/SettingsTable.module.css similarity index 100% rename from components/common/SettingsTable.module.css rename to src/components/common/SettingsTable.module.css diff --git a/components/common/UpdateNotice.js b/src/components/common/UpdateNotice.js similarity index 96% rename from components/common/UpdateNotice.js rename to src/components/common/UpdateNotice.js index bef6be98..e3edc70c 100644 --- a/components/common/UpdateNotice.js +++ b/src/components/common/UpdateNotice.js @@ -4,7 +4,7 @@ import { setItem } from 'next-basics'; import useStore, { checkVersion } from 'store/version'; import { REPO_URL, VERSION_CHECK } from 'lib/constants'; import styles from './UpdateNotice.module.css'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; import { useRouter } from 'next/router'; export function UpdateNotice({ user, config }) { diff --git a/components/common/UpdateNotice.module.css b/src/components/common/UpdateNotice.module.css similarity index 100% rename from components/common/UpdateNotice.module.css rename to src/components/common/UpdateNotice.module.css diff --git a/components/common/WorldMap.js b/src/components/common/WorldMap.js similarity index 94% rename from components/common/WorldMap.js rename to src/components/common/WorldMap.js index 9c91e4a4..b593099b 100644 --- a/components/common/WorldMap.js +++ b/src/components/common/WorldMap.js @@ -5,9 +5,9 @@ import classNames from 'classnames'; import { colord } from 'colord'; import HoverTooltip from 'components/common/HoverTooltip'; import { ISO_COUNTRIES, MAP_FILE } from 'lib/constants'; -import useTheme from 'hooks/useTheme'; -import useCountryNames from 'hooks/useCountryNames'; -import useLocale from 'hooks/useLocale'; +import useTheme from 'components/hooks/useTheme'; +import useCountryNames from 'components/hooks/useCountryNames'; +import useLocale from 'components/hooks/useLocale'; import { formatLongNumber } from 'lib/format'; import { percentFilter } from 'lib/filters'; import styles from './WorldMap.module.css'; diff --git a/components/common/WorldMap.module.css b/src/components/common/WorldMap.module.css similarity index 100% rename from components/common/WorldMap.module.css rename to src/components/common/WorldMap.module.css diff --git a/components/declarations.d.ts b/src/components/declarations.d.ts similarity index 100% rename from components/declarations.d.ts rename to src/components/declarations.d.ts diff --git a/hooks/index.js b/src/components/hooks/index.js similarity index 100% rename from hooks/index.js rename to src/components/hooks/index.js diff --git a/hooks/useApi.ts b/src/components/hooks/useApi.ts similarity index 100% rename from hooks/useApi.ts rename to src/components/hooks/useApi.ts diff --git a/hooks/useApiFilter.ts b/src/components/hooks/useApiFilter.ts similarity index 100% rename from hooks/useApiFilter.ts rename to src/components/hooks/useApiFilter.ts diff --git a/hooks/useConfig.js b/src/components/hooks/useConfig.js similarity index 91% rename from hooks/useConfig.js rename to src/components/hooks/useConfig.js index 2dead15a..6b37c87b 100644 --- a/hooks/useConfig.js +++ b/src/components/hooks/useConfig.js @@ -1,6 +1,6 @@ import { useEffect } from 'react'; import useStore, { setConfig } from 'store/app'; -import useApi from 'hooks/useApi'; +import useApi from 'components/hooks/useApi'; let loading = false; diff --git a/hooks/useCountryNames.js b/src/components/hooks/useCountryNames.js similarity index 100% rename from hooks/useCountryNames.js rename to src/components/hooks/useCountryNames.js diff --git a/hooks/useDateRange.js b/src/components/hooks/useDateRange.js similarity index 100% rename from hooks/useDateRange.js rename to src/components/hooks/useDateRange.js diff --git a/hooks/useDocumentClick.js b/src/components/hooks/useDocumentClick.js similarity index 100% rename from hooks/useDocumentClick.js rename to src/components/hooks/useDocumentClick.js diff --git a/hooks/useEscapeKey.js b/src/components/hooks/useEscapeKey.js similarity index 100% rename from hooks/useEscapeKey.js rename to src/components/hooks/useEscapeKey.js diff --git a/hooks/useFilters.js b/src/components/hooks/useFilters.js similarity index 97% rename from hooks/useFilters.js rename to src/components/hooks/useFilters.js index 089f2ee8..e1a9a885 100644 --- a/hooks/useFilters.js +++ b/src/components/hooks/useFilters.js @@ -1,4 +1,4 @@ -import { useMessages } from 'hooks'; +import { useMessages } from './useMessages'; import { OPERATORS } from 'lib/constants'; export function useFilters() { diff --git a/hooks/useForceUpdate.js b/src/components/hooks/useForceUpdate.js similarity index 100% rename from hooks/useForceUpdate.js rename to src/components/hooks/useForceUpdate.js diff --git a/hooks/useFormat.js b/src/components/hooks/useFormat.js similarity index 100% rename from hooks/useFormat.js rename to src/components/hooks/useFormat.js diff --git a/hooks/useLanguageNames.js b/src/components/hooks/useLanguageNames.js similarity index 93% rename from hooks/useLanguageNames.js rename to src/components/hooks/useLanguageNames.js index ff59e93d..afcb0ba6 100644 --- a/hooks/useLanguageNames.js +++ b/src/components/hooks/useLanguageNames.js @@ -1,7 +1,7 @@ import { useState, useEffect } from 'react'; import { useRouter } from 'next/router'; import { httpGet } from 'next-basics'; -import enUS from 'public/intl/language/en-US.json'; +import enUS from 'public/intl/country/en-US.json'; const languageNames = { 'en-US': enUS, diff --git a/hooks/useLocale.js b/src/components/hooks/useLocale.js similarity index 92% rename from hooks/useLocale.js rename to src/components/hooks/useLocale.js index 86ca9904..1374af81 100644 --- a/hooks/useLocale.js +++ b/src/components/hooks/useLocale.js @@ -4,8 +4,8 @@ import { httpGet, setItem } from 'next-basics'; import { LOCALE_CONFIG } from 'lib/constants'; import { getDateLocale, getTextDirection } from 'lib/lang'; import useStore, { setLocale } from 'store/app'; -import useForceUpdate from 'hooks/useForceUpdate'; -import enUS from 'public/intl/messages/en-US.json'; +import useForceUpdate from 'components/hooks/useForceUpdate'; +import enUS from 'public/intl/country/en-US.json'; const messages = { 'en-US': enUS, diff --git a/hooks/useMessages.js b/src/components/hooks/useMessages.js similarity index 100% rename from hooks/useMessages.js rename to src/components/hooks/useMessages.js diff --git a/hooks/usePageQuery.js b/src/components/hooks/usePageQuery.js similarity index 100% rename from hooks/usePageQuery.js rename to src/components/hooks/usePageQuery.js diff --git a/hooks/useReport.js b/src/components/hooks/useReport.js similarity index 100% rename from hooks/useReport.js rename to src/components/hooks/useReport.js diff --git a/hooks/useReports.js b/src/components/hooks/useReports.js similarity index 94% rename from hooks/useReports.js rename to src/components/hooks/useReports.js index 932fa6dc..d9292aeb 100644 --- a/hooks/useReports.js +++ b/src/components/hooks/useReports.js @@ -1,6 +1,6 @@ import { useState } from 'react'; import useApi from './useApi'; -import useApiFilter from 'hooks/useApiFilter'; +import useApiFilter from 'components/hooks/useApiFilter'; export function useReports() { const [modified, setModified] = useState(Date.now()); diff --git a/hooks/useRequireLogin.js b/src/components/hooks/useRequireLogin.ts similarity index 58% rename from hooks/useRequireLogin.js rename to src/components/hooks/useRequireLogin.ts index 3a95c988..950bb60a 100644 --- a/hooks/useRequireLogin.js +++ b/src/components/hooks/useRequireLogin.ts @@ -1,9 +1,9 @@ import { useEffect } from 'react'; import { useRouter } from 'next/router'; -import useApi from 'hooks/useApi'; -import useUser from 'hooks/useUser'; +import useApi from 'components/hooks/useApi'; +import useUser from 'components/hooks/useUser'; -export function useRequireLogin() { +export function useRequireLogin(handler: (data?: object) => void) { const router = useRouter(); const { get } = useApi(); const { user, setUser } = useUser(); @@ -11,9 +11,9 @@ export function useRequireLogin() { useEffect(() => { async function loadUser() { try { - const { user } = await get('/auth/verify'); + const data = await get('/auth/verify'); - setUser(user); + setUser(typeof handler === 'function' ? handler(data) : (data as any)?.user); } catch { await router.push('/login'); } diff --git a/hooks/useShareToken.js b/src/components/hooks/useShareToken.js similarity index 100% rename from hooks/useShareToken.js rename to src/components/hooks/useShareToken.js diff --git a/hooks/useSticky.js b/src/components/hooks/useSticky.js similarity index 100% rename from hooks/useSticky.js rename to src/components/hooks/useSticky.js diff --git a/hooks/useTheme.js b/src/components/hooks/useTheme.js similarity index 100% rename from hooks/useTheme.js rename to src/components/hooks/useTheme.js diff --git a/hooks/useTimezone.js b/src/components/hooks/useTimezone.js similarity index 100% rename from hooks/useTimezone.js rename to src/components/hooks/useTimezone.js diff --git a/hooks/useUser.js b/src/components/hooks/useUser.ts similarity index 100% rename from hooks/useUser.js rename to src/components/hooks/useUser.ts diff --git a/hooks/useWebsite.js b/src/components/hooks/useWebsite.js similarity index 100% rename from hooks/useWebsite.js rename to src/components/hooks/useWebsite.js diff --git a/hooks/useWebsiteReports.js b/src/components/hooks/useWebsiteReports.js similarity index 94% rename from hooks/useWebsiteReports.js rename to src/components/hooks/useWebsiteReports.js index 3b7ec415..c637bc76 100644 --- a/hooks/useWebsiteReports.js +++ b/src/components/hooks/useWebsiteReports.js @@ -1,6 +1,6 @@ import { useState } from 'react'; import useApi from './useApi'; -import useApiFilter from 'hooks/useApiFilter'; +import useApiFilter from 'components/hooks/useApiFilter'; export function useWebsiteReports(websiteId) { const [modified, setModified] = useState(Date.now()); diff --git a/components/icons.ts b/src/components/icons.ts similarity index 98% rename from components/icons.ts rename to src/components/icons.ts index 01d7caf5..8eb1f8b0 100644 --- a/components/icons.ts +++ b/src/components/icons.ts @@ -22,7 +22,7 @@ import User from 'assets/user.svg'; import Users from 'assets/users.svg'; import Visitor from 'assets/visitor.svg'; -const icons = { +const icons: any = { ...Icons, AddUser, Bars, diff --git a/components/input/DateFilter.js b/src/components/input/DateFilter.js similarity index 81% rename from components/input/DateFilter.js rename to src/components/input/DateFilter.js index af4b69dd..9fde27ca 100644 --- a/components/input/DateFilter.js +++ b/src/components/input/DateFilter.js @@ -2,10 +2,10 @@ import { useState } from 'react'; import { Icon, Modal, Dropdown, Item, Text, Flexbox } from 'react-basics'; import { endOfYear, isSameDay } from 'date-fns'; import DatePickerForm from 'components/metrics/DatePickerForm'; -import useLocale from 'hooks/useLocale'; +import useLocale from 'components/hooks/useLocale'; import { formatDate } from 'lib/date'; import Icons from 'components/icons'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export function DateFilter({ value, @@ -13,6 +13,7 @@ export function DateFilter({ endDate, className, onChange, + selectedUnit, showAllTime = false, alignment = 'end', }) { @@ -66,7 +67,12 @@ export function DateFilter({ const renderValue = value => { return value.startsWith('range') ? ( - handleChange('custom')} /> + handleChange('custom')} + /> ) : ( options.find(e => e.value === value).label ); @@ -120,9 +126,11 @@ export function DateFilter({ ); } -const CustomRange = ({ startDate, endDate, onClick }) => { +const CustomRange = ({ startDate, endDate, selectedUnit, onClick }) => { const { locale } = useLocale(); + const monthFormat = +selectedUnit?.num === 1 && selectedUnit?.unit === 'month'; + function handleClick(e) { e.stopPropagation(); @@ -135,8 +143,14 @@ const CustomRange = ({ startDate, endDate, onClick }) => { - {formatDate(startDate, 'd LLL y', locale)} - {!isSameDay(startDate, endDate) && ` — ${formatDate(endDate, 'd LLL y', locale)}`} + {monthFormat ? ( + <>{formatDate(startDate, 'MMMM yyyy', locale)} + ) : ( + <> + {formatDate(startDate, 'd LLL y', locale)} + {!isSameDay(startDate, endDate) && ` — ${formatDate(endDate, 'd LLL y', locale)}`} + + )} ); diff --git a/components/input/LanguageButton.js b/src/components/input/LanguageButton.js similarity index 96% rename from components/input/LanguageButton.js rename to src/components/input/LanguageButton.js index d4c1cbc3..3c0d0cd6 100644 --- a/components/input/LanguageButton.js +++ b/src/components/input/LanguageButton.js @@ -1,7 +1,7 @@ import { Icon, Button, PopupTrigger, Popup, Text } from 'react-basics'; import classNames from 'classnames'; import { languages } from 'lib/lang'; -import useLocale from 'hooks/useLocale'; +import useLocale from 'components/hooks/useLocale'; import Icons from 'components/icons'; import styles from './LanguageButton.module.css'; diff --git a/components/input/LanguageButton.module.css b/src/components/input/LanguageButton.module.css similarity index 100% rename from components/input/LanguageButton.module.css rename to src/components/input/LanguageButton.module.css diff --git a/components/input/LogoutButton.js b/src/components/input/LogoutButton.js similarity index 84% rename from components/input/LogoutButton.js rename to src/components/input/LogoutButton.js index 4a15cd68..2b04a78a 100644 --- a/components/input/LogoutButton.js +++ b/src/components/input/LogoutButton.js @@ -1,11 +1,11 @@ import { Button, Icon, Icons, TooltipPopup } from 'react-basics'; import Link from 'next/link'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export function LogoutButton({ tooltipPosition = 'top' }) { const { formatMessage, labels } = useMessages(); return ( - + + + + + )} + + ); +} + +export default WebsiteDateFilter; diff --git a/components/input/WebsiteDateFilter.module.css b/src/components/input/WebsiteDateFilter.module.css similarity index 100% rename from components/input/WebsiteDateFilter.module.css rename to src/components/input/WebsiteDateFilter.module.css diff --git a/components/input/WebsiteSelect.js b/src/components/input/WebsiteSelect.js similarity index 87% rename from components/input/WebsiteSelect.js rename to src/components/input/WebsiteSelect.js index ae3ceb46..1bdc4608 100644 --- a/components/input/WebsiteSelect.js +++ b/src/components/input/WebsiteSelect.js @@ -1,6 +1,6 @@ import { Dropdown, Item } from 'react-basics'; -import useApi from 'hooks/useApi'; -import useMessages from 'hooks/useMessages'; +import useApi from 'components/hooks/useApi'; +import useMessages from 'components/hooks/useMessages'; export function WebsiteSelect({ websiteId, onSelect }) { const { formatMessage, labels } = useMessages(); diff --git a/components/layout/AppLayout.js b/src/components/layout/AppLayout.js similarity index 92% rename from components/layout/AppLayout.js rename to src/components/layout/AppLayout.js index 7ab74351..8fd637f3 100644 --- a/components/layout/AppLayout.js +++ b/src/components/layout/AppLayout.js @@ -2,7 +2,7 @@ import { Container } from 'react-basics'; import Head from 'next/head'; import NavBar from 'components/layout/NavBar'; import UpdateNotice from 'components/common/UpdateNotice'; -import { useRequireLogin, useConfig } from 'hooks'; +import { useRequireLogin, useConfig } from 'components/hooks'; import styles from './AppLayout.module.css'; export function AppLayout({ title, children }) { diff --git a/components/layout/AppLayout.module.css b/src/components/layout/AppLayout.module.css similarity index 100% rename from components/layout/AppLayout.module.css rename to src/components/layout/AppLayout.module.css diff --git a/components/layout/Footer.js b/src/components/layout/Footer.js similarity index 100% rename from components/layout/Footer.js rename to src/components/layout/Footer.js diff --git a/components/layout/Footer.module.css b/src/components/layout/Footer.module.css similarity index 100% rename from components/layout/Footer.module.css rename to src/components/layout/Footer.module.css diff --git a/components/layout/Grid.js b/src/components/layout/Grid.js similarity index 100% rename from components/layout/Grid.js rename to src/components/layout/Grid.js diff --git a/components/layout/Grid.module.css b/src/components/layout/Grid.module.css similarity index 100% rename from components/layout/Grid.module.css rename to src/components/layout/Grid.module.css diff --git a/components/layout/Header.js b/src/components/layout/Header.js similarity index 100% rename from components/layout/Header.js rename to src/components/layout/Header.js diff --git a/components/layout/Header.module.css b/src/components/layout/Header.module.css similarity index 100% rename from components/layout/Header.module.css rename to src/components/layout/Header.module.css diff --git a/components/layout/NavBar.js b/src/components/layout/NavBar.js similarity index 94% rename from components/layout/NavBar.js rename to src/components/layout/NavBar.js index e896b404..ec088175 100644 --- a/components/layout/NavBar.js +++ b/src/components/layout/NavBar.js @@ -6,8 +6,8 @@ import ThemeButton from 'components/input/ThemeButton'; import LanguageButton from 'components/input/LanguageButton'; import ProfileButton from 'components/input/ProfileButton'; import styles from './NavBar.module.css'; -import useConfig from 'hooks/useConfig'; -import useMessages from 'hooks/useMessages'; +import useConfig from 'components/hooks/useConfig'; +import useMessages from 'components/hooks/useMessages'; import { useRouter } from 'next/router'; import HamburgerButton from '../common/HamburgerButton'; diff --git a/components/layout/NavBar.module.css b/src/components/layout/NavBar.module.css similarity index 100% rename from components/layout/NavBar.module.css rename to src/components/layout/NavBar.module.css diff --git a/components/layout/NavGroup.js b/src/components/layout/NavGroup.js similarity index 100% rename from components/layout/NavGroup.js rename to src/components/layout/NavGroup.js diff --git a/components/layout/NavGroup.module.css b/src/components/layout/NavGroup.module.css similarity index 100% rename from components/layout/NavGroup.module.css rename to src/components/layout/NavGroup.module.css diff --git a/components/layout/Page.js b/src/components/layout/Page.js similarity index 90% rename from components/layout/Page.js rename to src/components/layout/Page.js index 30abde50..4f42aa55 100644 --- a/components/layout/Page.js +++ b/src/components/layout/Page.js @@ -1,6 +1,6 @@ import classNames from 'classnames'; import { Banner, Loading } from 'react-basics'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; import styles from './Page.module.css'; export function Page({ className, error, loading, children }) { diff --git a/components/layout/Page.module.css b/src/components/layout/Page.module.css similarity index 100% rename from components/layout/Page.module.css rename to src/components/layout/Page.module.css diff --git a/components/layout/PageHeader.js b/src/components/layout/PageHeader.js similarity index 100% rename from components/layout/PageHeader.js rename to src/components/layout/PageHeader.js diff --git a/components/layout/PageHeader.module.css b/src/components/layout/PageHeader.module.css similarity index 100% rename from components/layout/PageHeader.module.css rename to src/components/layout/PageHeader.module.css diff --git a/components/layout/ReportsLayout.js b/src/components/layout/ReportsLayout.js similarity index 83% rename from components/layout/ReportsLayout.js rename to src/components/layout/ReportsLayout.js index fd63a67e..374da263 100644 --- a/components/layout/ReportsLayout.js +++ b/src/components/layout/ReportsLayout.js @@ -1,7 +1,7 @@ import { Column, Row } from 'react-basics'; import styles from './ReportsLayout.module.css'; -export function SettingsLayout({ children, filter, header }) { +export function ReportsLayout({ children, filter, header }) { return ( <> {header} @@ -20,4 +20,4 @@ export function SettingsLayout({ children, filter, header }) { ); } -export default SettingsLayout; +export default ReportsLayout; diff --git a/components/layout/ReportsLayout.module.css b/src/components/layout/ReportsLayout.module.css similarity index 100% rename from components/layout/ReportsLayout.module.css rename to src/components/layout/ReportsLayout.module.css diff --git a/components/layout/SettingsLayout.js b/src/components/layout/SettingsLayout.js similarity index 88% rename from components/layout/SettingsLayout.js rename to src/components/layout/SettingsLayout.js index c79f0909..851c366a 100644 --- a/components/layout/SettingsLayout.js +++ b/src/components/layout/SettingsLayout.js @@ -1,9 +1,9 @@ import { Row, Column } from 'react-basics'; import { useRouter } from 'next/router'; import SideNav from './SideNav'; -import useUser from 'hooks/useUser'; -import useMessages from 'hooks/useMessages'; -import useConfig from 'hooks/useConfig'; +import useUser from 'components/hooks/useUser'; +import useMessages from 'components/hooks/useMessages'; +import useConfig from 'components/hooks/useConfig'; import styles from './SettingsLayout.module.css'; export function SettingsLayout({ children }) { diff --git a/components/layout/SettingsLayout.module.css b/src/components/layout/SettingsLayout.module.css similarity index 100% rename from components/layout/SettingsLayout.module.css rename to src/components/layout/SettingsLayout.module.css diff --git a/components/layout/ShareLayout.js b/src/components/layout/ShareLayout.js similarity index 100% rename from components/layout/ShareLayout.js rename to src/components/layout/ShareLayout.js diff --git a/components/layout/SideNav.js b/src/components/layout/SideNav.js similarity index 100% rename from components/layout/SideNav.js rename to src/components/layout/SideNav.js diff --git a/components/layout/SideNav.module.css b/src/components/layout/SideNav.module.css similarity index 100% rename from components/layout/SideNav.module.css rename to src/components/layout/SideNav.module.css diff --git a/components/messages.js b/src/components/messages.js similarity index 99% rename from components/messages.js rename to src/components/messages.js index ff619945..f52ed5c5 100644 --- a/components/messages.js +++ b/src/components/messages.js @@ -140,6 +140,7 @@ export const labels = defineMessages({ description: { id: 'label.description', defaultMessage: 'Description' }, untitled: { id: 'label.untitled', defaultMessage: 'Untitled' }, type: { id: 'label.type', defaultMessage: 'Type' }, + filter: { id: 'label.filter', defaultMessage: 'Filter' }, filters: { id: 'label.filters', defaultMessage: 'Filters' }, breakdown: { id: 'label.breakdown', defaultMessage: 'Breakdown' }, true: { id: 'label.true', defaultMessage: 'True' }, diff --git a/components/metrics/ActiveUsers.js b/src/components/metrics/ActiveUsers.js similarity index 89% rename from components/metrics/ActiveUsers.js rename to src/components/metrics/ActiveUsers.js index 64051946..3074d0df 100644 --- a/components/metrics/ActiveUsers.js +++ b/src/components/metrics/ActiveUsers.js @@ -1,7 +1,7 @@ import { useMemo } from 'react'; import { StatusLight } from 'react-basics'; -import useApi from 'hooks/useApi'; -import useMessages from 'hooks/useMessages'; +import useApi from 'components/hooks/useApi'; +import useMessages from 'components/hooks/useMessages'; import styles from './ActiveUsers.module.css'; export function ActiveUsers({ websiteId, value, refetchInterval = 60000 }) { diff --git a/components/metrics/ActiveUsers.module.css b/src/components/metrics/ActiveUsers.module.css similarity index 100% rename from components/metrics/ActiveUsers.module.css rename to src/components/metrics/ActiveUsers.module.css diff --git a/components/metrics/BarChart.js b/src/components/metrics/BarChart.js similarity index 97% rename from components/metrics/BarChart.js rename to src/components/metrics/BarChart.js index c086017e..7b94c147 100644 --- a/components/metrics/BarChart.js +++ b/src/components/metrics/BarChart.js @@ -4,8 +4,8 @@ import classNames from 'classnames'; import Chart from 'chart.js/auto'; import HoverTooltip from 'components/common/HoverTooltip'; import Legend from 'components/metrics/Legend'; -import useLocale from 'hooks/useLocale'; -import useTheme from 'hooks/useTheme'; +import useLocale from 'components/hooks/useLocale'; +import useTheme from 'components/hooks/useTheme'; import { DEFAULT_ANIMATION_DURATION } from 'lib/constants'; import { renderNumberLabels } from 'lib/charts'; import styles from './BarChart.module.css'; diff --git a/components/metrics/BarChart.module.css b/src/components/metrics/BarChart.module.css similarity index 100% rename from components/metrics/BarChart.module.css rename to src/components/metrics/BarChart.module.css diff --git a/components/metrics/BrowsersTable.js b/src/components/metrics/BrowsersTable.js similarity index 89% rename from components/metrics/BrowsersTable.js rename to src/components/metrics/BrowsersTable.js index bf4d0aaa..e68b159f 100644 --- a/components/metrics/BrowsersTable.js +++ b/src/components/metrics/BrowsersTable.js @@ -1,8 +1,8 @@ import { useRouter } from 'next/router'; import FilterLink from 'components/common/FilterLink'; import MetricsTable from 'components/metrics/MetricsTable'; -import useMessages from 'hooks/useMessages'; -import useFormat from 'hooks/useFormat'; +import useMessages from 'components/hooks/useMessages'; +import useFormat from 'components/hooks/useFormat'; export function BrowsersTable({ websiteId, ...props }) { const { formatMessage, labels } = useMessages(); diff --git a/components/metrics/CitiesTable.js b/src/components/metrics/CitiesTable.js similarity index 86% rename from components/metrics/CitiesTable.js rename to src/components/metrics/CitiesTable.js index 2e74780d..fcdc8f88 100644 --- a/components/metrics/CitiesTable.js +++ b/src/components/metrics/CitiesTable.js @@ -1,8 +1,8 @@ import MetricsTable from './MetricsTable'; import { emptyFilter } from 'lib/filters'; import FilterLink from 'components/common/FilterLink'; -import useLocale from 'hooks/useLocale'; -import useMessages from 'hooks/useMessages'; +import useLocale from 'components/hooks/useLocale'; +import useMessages from 'components/hooks/useMessages'; export function CitiesTable({ websiteId, ...props }) { const { locale } = useLocale(); diff --git a/components/metrics/CountriesTable.js b/src/components/metrics/CountriesTable.js similarity index 88% rename from components/metrics/CountriesTable.js rename to src/components/metrics/CountriesTable.js index 283fdaf2..ec7ab73d 100644 --- a/components/metrics/CountriesTable.js +++ b/src/components/metrics/CountriesTable.js @@ -1,7 +1,7 @@ import { useRouter } from 'next/router'; import FilterLink from 'components/common/FilterLink'; -import useCountryNames from 'hooks/useCountryNames'; -import { useLocale, useMessages, useFormat } from 'hooks'; +import useCountryNames from 'components/hooks/useCountryNames'; +import { useLocale, useMessages, useFormat } from 'components/hooks'; import MetricsTable from './MetricsTable'; export function CountriesTable({ websiteId, ...props }) { diff --git a/components/metrics/DataTable.js b/src/components/metrics/DataTable.js similarity index 98% rename from components/metrics/DataTable.js rename to src/components/metrics/DataTable.js index e2e9462d..b578ffde 100644 --- a/components/metrics/DataTable.js +++ b/src/components/metrics/DataTable.js @@ -5,7 +5,7 @@ import { useSpring, animated, config } from 'react-spring'; import classNames from 'classnames'; import Empty from 'components/common/Empty'; import { formatNumber, formatLongNumber } from 'lib/format'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; import styles from './DataTable.module.css'; export function DataTable({ diff --git a/components/metrics/DataTable.module.css b/src/components/metrics/DataTable.module.css similarity index 100% rename from components/metrics/DataTable.module.css rename to src/components/metrics/DataTable.module.css diff --git a/components/metrics/DatePickerForm.js b/src/components/metrics/DatePickerForm.js similarity index 96% rename from components/metrics/DatePickerForm.js rename to src/components/metrics/DatePickerForm.js index 53f027bb..fa45b64a 100644 --- a/components/metrics/DatePickerForm.js +++ b/src/components/metrics/DatePickerForm.js @@ -1,10 +1,10 @@ import { useState } from 'react'; import { Button, ButtonGroup, Calendar } from 'react-basics'; import { isAfter, isBefore, isSameDay } from 'date-fns'; -import useLocale from 'hooks/useLocale'; +import useLocale from 'components/hooks/useLocale'; import { getDateLocale } from 'lib/lang'; import { FILTER_DAY, FILTER_RANGE } from 'lib/constants'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; import styles from './DatePickerForm.module.css'; export function DatePickerForm({ diff --git a/components/metrics/DatePickerForm.module.css b/src/components/metrics/DatePickerForm.module.css similarity index 100% rename from components/metrics/DatePickerForm.module.css rename to src/components/metrics/DatePickerForm.module.css diff --git a/components/metrics/DevicesTable.js b/src/components/metrics/DevicesTable.js similarity index 90% rename from components/metrics/DevicesTable.js rename to src/components/metrics/DevicesTable.js index 98690d0a..7b591552 100644 --- a/components/metrics/DevicesTable.js +++ b/src/components/metrics/DevicesTable.js @@ -1,8 +1,8 @@ import MetricsTable from './MetricsTable'; import FilterLink from 'components/common/FilterLink'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; import { useRouter } from 'next/router'; -import { useFormat } from 'hooks'; +import { useFormat } from 'components/hooks'; export function DevicesTable({ websiteId, ...props }) { const { formatMessage, labels } = useMessages(); diff --git a/components/metrics/EventsChart.js b/src/components/metrics/EventsChart.js similarity index 98% rename from components/metrics/EventsChart.js rename to src/components/metrics/EventsChart.js index 82b8c8f7..f1964c15 100644 --- a/components/metrics/EventsChart.js +++ b/src/components/metrics/EventsChart.js @@ -3,7 +3,7 @@ import { Loading } from 'react-basics'; import { colord } from 'colord'; import BarChart from './BarChart'; import { getDateArray } from 'lib/date'; -import { useApi, useLocale, useDateRange, useTimezone, usePageQuery } from 'hooks'; +import { useApi, useLocale, useDateRange, useTimezone, usePageQuery } from 'components/hooks'; import { EVENT_COLORS } from 'lib/constants'; import { renderDateLabels, renderStatusTooltipPopup } from 'lib/charts'; diff --git a/components/metrics/EventsChart.module.css b/src/components/metrics/EventsChart.module.css similarity index 100% rename from components/metrics/EventsChart.module.css rename to src/components/metrics/EventsChart.module.css diff --git a/components/metrics/EventsTable.js b/src/components/metrics/EventsTable.js similarity index 89% rename from components/metrics/EventsTable.js rename to src/components/metrics/EventsTable.js index eb23a281..a8ae82aa 100644 --- a/components/metrics/EventsTable.js +++ b/src/components/metrics/EventsTable.js @@ -1,5 +1,5 @@ import MetricsTable from './MetricsTable'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export function EventsTable({ websiteId, ...props }) { const { formatMessage, labels } = useMessages(); diff --git a/components/metrics/FilterTags.js b/src/components/metrics/FilterTags.js similarity index 92% rename from components/metrics/FilterTags.js rename to src/components/metrics/FilterTags.js index ad3ff60b..30857a6b 100644 --- a/components/metrics/FilterTags.js +++ b/src/components/metrics/FilterTags.js @@ -1,8 +1,8 @@ import { safeDecodeURI } from 'next-basics'; import { Button, Icon, Icons, Text } from 'react-basics'; -import usePageQuery from 'hooks/usePageQuery'; +import usePageQuery from 'components/hooks/usePageQuery'; import styles from './FilterTags.module.css'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export function FilterTags({ params }) { const { formatMessage, labels } = useMessages(); diff --git a/components/metrics/FilterTags.module.css b/src/components/metrics/FilterTags.module.css similarity index 100% rename from components/metrics/FilterTags.module.css rename to src/components/metrics/FilterTags.module.css diff --git a/components/metrics/LanguagesTable.js b/src/components/metrics/LanguagesTable.js similarity index 81% rename from components/metrics/LanguagesTable.js rename to src/components/metrics/LanguagesTable.js index e90a3425..7d220829 100644 --- a/components/metrics/LanguagesTable.js +++ b/src/components/metrics/LanguagesTable.js @@ -1,8 +1,8 @@ import MetricsTable from './MetricsTable'; import { percentFilter } from 'lib/filters'; -import useLanguageNames from 'hooks/useLanguageNames'; -import useLocale from 'hooks/useLocale'; -import useMessages from 'hooks/useMessages'; +import useLanguageNames from 'components/hooks/useLanguageNames'; +import useLocale from 'components/hooks/useLocale'; +import useMessages from 'components/hooks/useMessages'; export function LanguagesTable({ websiteId, onDataLoad, ...props }) { const { formatMessage, labels } = useMessages(); diff --git a/components/metrics/Legend.js b/src/components/metrics/Legend.js similarity index 89% rename from components/metrics/Legend.js rename to src/components/metrics/Legend.js index 91135acb..ce8a3381 100644 --- a/components/metrics/Legend.js +++ b/src/components/metrics/Legend.js @@ -2,8 +2,8 @@ import { useEffect } from 'react'; import { StatusLight } from 'react-basics'; import { colord } from 'colord'; import classNames from 'classnames'; -import useLocale from 'hooks/useLocale'; -import useForceUpdate from 'hooks/useForceUpdate'; +import useLocale from 'components/hooks/useLocale'; +import useForceUpdate from 'components/hooks/useForceUpdate'; import styles from './Legend.module.css'; export function Legend({ chart }) { @@ -22,7 +22,7 @@ export function Legend({ chart }) { useEffect(() => { forceUpdate(); - }, [locale]); + }, [locale, forceUpdate]); if (!chart?.legend?.legendItems.find(({ text }) => text)) { return null; diff --git a/components/metrics/Legend.module.css b/src/components/metrics/Legend.module.css similarity index 100% rename from components/metrics/Legend.module.css rename to src/components/metrics/Legend.module.css diff --git a/components/metrics/MetricCard.js b/src/components/metrics/MetricCard.js similarity index 100% rename from components/metrics/MetricCard.js rename to src/components/metrics/MetricCard.js diff --git a/components/metrics/MetricCard.module.css b/src/components/metrics/MetricCard.module.css similarity index 100% rename from components/metrics/MetricCard.module.css rename to src/components/metrics/MetricCard.module.css diff --git a/components/metrics/MetricsBar.js b/src/components/metrics/MetricsBar.js similarity index 100% rename from components/metrics/MetricsBar.js rename to src/components/metrics/MetricsBar.js diff --git a/components/metrics/MetricsBar.module.css b/src/components/metrics/MetricsBar.module.css similarity index 100% rename from components/metrics/MetricsBar.module.css rename to src/components/metrics/MetricsBar.module.css diff --git a/components/metrics/MetricsTable.js b/src/components/metrics/MetricsTable.js similarity index 90% rename from components/metrics/MetricsTable.js rename to src/components/metrics/MetricsTable.js index 50262798..893427a5 100644 --- a/components/metrics/MetricsTable.js +++ b/src/components/metrics/MetricsTable.js @@ -3,17 +3,17 @@ import { Loading, Icon, Text, Button } from 'react-basics'; import Link from 'next/link'; import firstBy from 'thenby'; import classNames from 'classnames'; -import useApi from 'hooks/useApi'; +import useApi from 'components/hooks/useApi'; import { percentFilter } from 'lib/filters'; -import useDateRange from 'hooks/useDateRange'; -import usePageQuery from 'hooks/usePageQuery'; +import useDateRange from 'components/hooks/useDateRange'; +import usePageQuery from 'components/hooks/usePageQuery'; import ErrorMessage from 'components/common/ErrorMessage'; import DataTable from './DataTable'; import { DEFAULT_ANIMATION_DURATION } from 'lib/constants'; import Icons from 'components/icons'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; import styles from './MetricsTable.module.css'; -import useLocale from 'hooks/useLocale'; +import useLocale from 'components/hooks/useLocale'; export function MetricsTable({ websiteId, @@ -34,6 +34,7 @@ export function MetricsTable({ } = usePageQuery(); const { formatMessage, labels } = useMessages(); const { get, useQuery } = useApi(); + const { dir } = useLocale(); const { data, isLoading, isFetched, error } = useQuery( [ @@ -97,8 +98,7 @@ export function MetricsTable({ return items.sort(firstBy('y', -1).thenBy('x')); } return []; - }, [data, error, dataFilter, filterOptions]); - const { dir } = useLocale(); + }, [data, error, dataFilter, filterOptions, limit]); return (
diff --git a/components/metrics/MetricsTable.module.css b/src/components/metrics/MetricsTable.module.css similarity index 100% rename from components/metrics/MetricsTable.module.css rename to src/components/metrics/MetricsTable.module.css diff --git a/components/metrics/OSTable.js b/src/components/metrics/OSTable.js similarity index 93% rename from components/metrics/OSTable.js rename to src/components/metrics/OSTable.js index e4bc3234..90135124 100644 --- a/components/metrics/OSTable.js +++ b/src/components/metrics/OSTable.js @@ -1,6 +1,6 @@ import MetricsTable from './MetricsTable'; import FilterLink from 'components/common/FilterLink'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; import { useRouter } from 'next/router'; export function OSTable({ websiteId, ...props }) { diff --git a/components/metrics/PagesTable.js b/src/components/metrics/PagesTable.js similarity index 91% rename from components/metrics/PagesTable.js rename to src/components/metrics/PagesTable.js index 47e70318..f310643e 100644 --- a/components/metrics/PagesTable.js +++ b/src/components/metrics/PagesTable.js @@ -1,8 +1,8 @@ import FilterLink from 'components/common/FilterLink'; import FilterButtons from 'components/common/FilterButtons'; import MetricsTable from './MetricsTable'; -import useMessages from 'hooks/useMessages'; -import usePageQuery from 'hooks/usePageQuery'; +import useMessages from 'components/hooks/useMessages'; +import usePageQuery from 'components/hooks/usePageQuery'; import { emptyFilter } from 'lib/filters'; export function PagesTable({ websiteId, showFilters, ...props }) { diff --git a/components/metrics/PageviewsChart.js b/src/components/metrics/PageviewsChart.js similarity index 90% rename from components/metrics/PageviewsChart.js rename to src/components/metrics/PageviewsChart.js index 1b481c48..096278f3 100644 --- a/components/metrics/PageviewsChart.js +++ b/src/components/metrics/PageviewsChart.js @@ -1,6 +1,6 @@ import { useMemo } from 'react'; import BarChart from './BarChart'; -import { useLocale, useTheme, useMessages } from 'hooks'; +import { useLocale, useTheme, useMessages } from 'components/hooks'; import { renderDateLabels, renderStatusTooltipPopup } from 'lib/charts'; export function PageviewsChart({ websiteId, data, unit, loading, ...props }) { @@ -25,7 +25,7 @@ export function PageviewsChart({ websiteId, data, unit, loading, ...props }) { ...colors.chart.views, }, ]; - }, [data, locale, colors]); + }, [data, colors, formatMessage, labels]); return ( __id); diff --git a/components/pages/realtime/RealtimePage.module.css b/src/components/pages/realtime/RealtimePage.module.css similarity index 100% rename from components/pages/realtime/RealtimePage.module.css rename to src/components/pages/realtime/RealtimePage.module.css diff --git a/components/pages/realtime/RealtimeUrls.js b/src/components/pages/realtime/RealtimeUrls.js similarity index 97% rename from components/pages/realtime/RealtimeUrls.js rename to src/components/pages/realtime/RealtimeUrls.js index 18d8f2f6..4041a5d8 100644 --- a/components/pages/realtime/RealtimeUrls.js +++ b/src/components/pages/realtime/RealtimeUrls.js @@ -4,7 +4,7 @@ import firstBy from 'thenby'; import { percentFilter } from 'lib/filters'; import DataTable from 'components/metrics/DataTable'; import { FILTER_PAGES, FILTER_REFERRERS } from 'lib/constants'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export function RealtimeUrls({ websiteDomain, data = {} }) { const { formatMessage, labels } = useMessages(); diff --git a/components/pages/reports/BaseParameters.js b/src/components/pages/reports/BaseParameters.js similarity index 97% rename from components/pages/reports/BaseParameters.js rename to src/components/pages/reports/BaseParameters.js index 76c35a58..44a9da5b 100644 --- a/components/pages/reports/BaseParameters.js +++ b/src/components/pages/reports/BaseParameters.js @@ -4,7 +4,7 @@ import WebsiteSelect from 'components/input/WebsiteSelect'; import { parseDateRange } from 'lib/date'; import { useContext } from 'react'; import { ReportContext } from './Report'; -import { useMessages } from 'hooks'; +import { useMessages } from 'components/hooks'; export function BaseParameters({ showWebsiteSelect = true, diff --git a/components/pages/reports/FieldAddForm.js b/src/components/pages/reports/FieldAddForm.js similarity index 100% rename from components/pages/reports/FieldAddForm.js rename to src/components/pages/reports/FieldAddForm.js diff --git a/components/pages/reports/FieldAddForm.module.css b/src/components/pages/reports/FieldAddForm.module.css similarity index 100% rename from components/pages/reports/FieldAddForm.module.css rename to src/components/pages/reports/FieldAddForm.module.css diff --git a/components/pages/reports/FieldAggregateForm.js b/src/components/pages/reports/FieldAggregateForm.js similarity index 96% rename from components/pages/reports/FieldAggregateForm.js rename to src/components/pages/reports/FieldAggregateForm.js index abd1dbd9..34b67980 100644 --- a/components/pages/reports/FieldAggregateForm.js +++ b/src/components/pages/reports/FieldAggregateForm.js @@ -1,5 +1,5 @@ import { Form, FormRow, Menu, Item } from 'react-basics'; -import { useMessages } from 'hooks'; +import { useMessages } from 'components/hooks'; export default function FieldAggregateForm({ name, type, onSelect }) { const { formatMessage, labels } = useMessages(); diff --git a/components/pages/reports/FieldFilterForm.js b/src/components/pages/reports/FieldFilterForm.js similarity index 68% rename from components/pages/reports/FieldFilterForm.js rename to src/components/pages/reports/FieldFilterForm.js index 3df8f745..01efed3f 100644 --- a/components/pages/reports/FieldFilterForm.js +++ b/src/components/pages/reports/FieldFilterForm.js @@ -1,9 +1,16 @@ import { useState } from 'react'; import { Form, FormRow, Item, Flexbox, Dropdown, Button } from 'react-basics'; -import { useMessages, useFilters, useFormat } from 'hooks'; +import { useMessages, useFilters, useFormat } from 'components/hooks'; import styles from './FieldFilterForm.module.css'; -export default function FieldFilterForm({ name, label, type, values, onSelect }) { +export default function FieldFilterForm({ + name, + label, + type, + values, + onSelect, + includeOnlyEquals, +}) { const { formatMessage, labels } = useMessages(); const [filter, setFilter] = useState('eq'); const [value, setValue] = useState(); @@ -27,17 +34,19 @@ export default function FieldFilterForm({ name, label, type, values, onSelect })
- - {({ value, label }) => { - return {label}; - }} - + {!includeOnlyEquals && ( + + {({ value, label }) => { + return {label}; + }} + + )} {value => { return {formatValue(value, name)}; diff --git a/components/pages/reports/FieldFilterForm.module.css b/src/components/pages/reports/FieldFilterForm.module.css similarity index 100% rename from components/pages/reports/FieldFilterForm.module.css rename to src/components/pages/reports/FieldFilterForm.module.css diff --git a/components/pages/reports/FieldSelectForm.js b/src/components/pages/reports/FieldSelectForm.js similarity index 94% rename from components/pages/reports/FieldSelectForm.js rename to src/components/pages/reports/FieldSelectForm.js index 434a5ae7..e7661511 100644 --- a/components/pages/reports/FieldSelectForm.js +++ b/src/components/pages/reports/FieldSelectForm.js @@ -1,5 +1,5 @@ import { Menu, Item, Form, FormRow } from 'react-basics'; -import { useMessages } from 'hooks'; +import { useMessages } from 'components/hooks'; import styles from './FieldSelectForm.module.css'; export default function FieldSelectForm({ items, onSelect, showType = true }) { diff --git a/components/pages/reports/FieldSelectForm.module.css b/src/components/pages/reports/FieldSelectForm.module.css similarity index 100% rename from components/pages/reports/FieldSelectForm.module.css rename to src/components/pages/reports/FieldSelectForm.module.css diff --git a/components/pages/reports/FilterSelectForm.js b/src/components/pages/reports/FilterSelectForm.js similarity index 89% rename from components/pages/reports/FilterSelectForm.js rename to src/components/pages/reports/FilterSelectForm.js index 38094bca..8e02930e 100644 --- a/components/pages/reports/FilterSelectForm.js +++ b/src/components/pages/reports/FilterSelectForm.js @@ -1,7 +1,7 @@ import { useState } from 'react'; import FieldSelectForm from './FieldSelectForm'; import FieldFilterForm from './FieldFilterForm'; -import { useApi } from 'hooks'; +import { useApi } from 'components/hooks'; import { Loading } from 'react-basics'; function useValues(websiteId, type) { @@ -18,7 +18,7 @@ function useValues(websiteId, type) { return { data, error, isLoading }; } -export default function FilterSelectForm({ websiteId, items, onSelect }) { +export default function FilterSelectForm({ websiteId, items, onSelect, includeOnlyEquals }) { const [field, setField] = useState(); const { data, isLoading } = useValues(websiteId, field?.name); @@ -37,6 +37,7 @@ export default function FilterSelectForm({ websiteId, items, onSelect }) { type={field?.type} values={data} onSelect={onSelect} + includeOnlyEquals={includeOnlyEquals} /> ); } diff --git a/components/pages/reports/ParameterList.js b/src/components/pages/reports/ParameterList.js similarity index 95% rename from components/pages/reports/ParameterList.js rename to src/components/pages/reports/ParameterList.js index a097cbdc..bf77dd9d 100644 --- a/components/pages/reports/ParameterList.js +++ b/src/components/pages/reports/ParameterList.js @@ -1,7 +1,7 @@ import { Icon, TooltipPopup } from 'react-basics'; import Icons from 'components/icons'; import Empty from 'components/common/Empty'; -import { useMessages } from 'hooks'; +import { useMessages } from 'components/hooks'; import styles from './ParameterList.module.css'; export function ParameterList({ items = [], children, onRemove }) { diff --git a/components/pages/reports/ParameterList.module.css b/src/components/pages/reports/ParameterList.module.css similarity index 100% rename from components/pages/reports/ParameterList.module.css rename to src/components/pages/reports/ParameterList.module.css diff --git a/components/pages/reports/PopupForm.js b/src/components/pages/reports/PopupForm.js similarity index 100% rename from components/pages/reports/PopupForm.js rename to src/components/pages/reports/PopupForm.js diff --git a/components/pages/reports/PopupForm.module.css b/src/components/pages/reports/PopupForm.module.css similarity index 100% rename from components/pages/reports/PopupForm.module.css rename to src/components/pages/reports/PopupForm.module.css diff --git a/components/pages/reports/Report.js b/src/components/pages/reports/Report.js similarity index 92% rename from components/pages/reports/Report.js rename to src/components/pages/reports/Report.js index 685ebb9f..de17aca6 100644 --- a/components/pages/reports/Report.js +++ b/src/components/pages/reports/Report.js @@ -1,7 +1,7 @@ import { createContext } from 'react'; import Page from 'components/layout/Page'; import styles from './reports.module.css'; -import { useReport } from 'hooks'; +import { useReport } from 'components/hooks'; export const ReportContext = createContext(null); diff --git a/components/pages/reports/ReportBody.js b/src/components/pages/reports/ReportBody.js similarity index 100% rename from components/pages/reports/ReportBody.js rename to src/components/pages/reports/ReportBody.js diff --git a/components/pages/reports/ReportDetails.js b/src/components/pages/reports/ReportDetails.js similarity index 100% rename from components/pages/reports/ReportDetails.js rename to src/components/pages/reports/ReportDetails.js diff --git a/components/pages/reports/ReportHeader.js b/src/components/pages/reports/ReportHeader.js similarity index 96% rename from components/pages/reports/ReportHeader.js rename to src/components/pages/reports/ReportHeader.js index 394b1951..e81d6ece 100644 --- a/components/pages/reports/ReportHeader.js +++ b/src/components/pages/reports/ReportHeader.js @@ -2,7 +2,7 @@ import { useContext } from 'react'; import { useRouter } from 'next/router'; import { Icon, LoadingButton, InlineEditField, useToasts } from 'react-basics'; import PageHeader from 'components/layout/PageHeader'; -import { useMessages, useApi } from 'hooks'; +import { useMessages, useApi } from 'components/hooks'; import { ReportContext } from './Report'; import styles from './ReportHeader.module.css'; import reportStyles from './reports.module.css'; @@ -66,7 +66,7 @@ export function ReportHeader({ icon }) { }> diff --git a/components/pages/reports/ReportHeader.module.css b/src/components/pages/reports/ReportHeader.module.css similarity index 100% rename from components/pages/reports/ReportHeader.module.css rename to src/components/pages/reports/ReportHeader.module.css diff --git a/components/pages/reports/ReportMenu.js b/src/components/pages/reports/ReportMenu.js similarity index 100% rename from components/pages/reports/ReportMenu.js rename to src/components/pages/reports/ReportMenu.js diff --git a/components/pages/reports/ReportTemplates.js b/src/components/pages/reports/ReportTemplates.js similarity index 91% rename from components/pages/reports/ReportTemplates.js rename to src/components/pages/reports/ReportTemplates.js index 0f5e710d..2b934434 100644 --- a/components/pages/reports/ReportTemplates.js +++ b/src/components/pages/reports/ReportTemplates.js @@ -6,7 +6,7 @@ import Funnel from 'assets/funnel.svg'; import Lightbulb from 'assets/lightbulb.svg'; import Magnet from 'assets/magnet.svg'; import styles from './ReportTemplates.module.css'; -import { useMessages } from 'hooks'; +import { useMessages } from 'components/hooks'; function ReportItem({ title, description, url, icon }) { return ( @@ -30,7 +30,7 @@ function ReportItem({ title, description, url, icon }) { ); } -export function ReportTemplates() { +export function ReportTemplates({ showHeader = true }) { const { formatMessage, labels } = useMessages(); const reports = [ @@ -56,7 +56,7 @@ export function ReportTemplates() { return ( - + {showHeader && }
{reports.map(({ title, description, url, icon }) => { return ( diff --git a/components/pages/reports/ReportTemplates.module.css b/src/components/pages/reports/ReportTemplates.module.css similarity index 100% rename from components/pages/reports/ReportTemplates.module.css rename to src/components/pages/reports/ReportTemplates.module.css diff --git a/components/pages/reports/ReportsPage.js b/src/components/pages/reports/ReportsPage.js similarity index 85% rename from components/pages/reports/ReportsPage.js rename to src/components/pages/reports/ReportsPage.js index 95959832..bbb15a36 100644 --- a/components/pages/reports/ReportsPage.js +++ b/src/components/pages/reports/ReportsPage.js @@ -1,13 +1,13 @@ import EmptyPlaceholder from 'components/common/EmptyPlaceholder'; import Page from 'components/layout/Page'; import PageHeader from 'components/layout/PageHeader'; -import { useMessages, useReports } from 'hooks'; +import { useMessages, useReports } from 'components/hooks'; import Link from 'next/link'; import { Button, Icon, Icons, Text } from 'react-basics'; import ReportsTable from './ReportsTable'; export function ReportsPage() { - const { formatMessage, labels, messages } = useMessages(); + const { formatMessage, labels } = useMessages(); const { reports, error, @@ -47,9 +47,7 @@ export function ReportsPage() { showDomain={true} /> )} - {!hasData && ( - - )} + {!hasData && } ); } diff --git a/components/pages/reports/ReportsTable.js b/src/components/pages/reports/ReportsTable.js similarity index 95% rename from components/pages/reports/ReportsTable.js rename to src/components/pages/reports/ReportsTable.js index 98f5267a..4073fbec 100644 --- a/components/pages/reports/ReportsTable.js +++ b/src/components/pages/reports/ReportsTable.js @@ -1,8 +1,8 @@ import ConfirmDeleteForm from 'components/common/ConfirmDeleteForm'; import LinkButton from 'components/common/LinkButton'; import SettingsTable from 'components/common/SettingsTable'; -import { useMessages } from 'hooks'; -import useUser from 'hooks/useUser'; +import { useMessages } from 'components/hooks'; +import useUser from 'components/hooks/useUser'; import { useState } from 'react'; import { Button, Flexbox, Icon, Icons, Modal, Text } from 'react-basics'; diff --git a/components/pages/reports/event-data/EventDataParameters.js b/src/components/pages/reports/event-data/EventDataParameters.js similarity index 98% rename from components/pages/reports/event-data/EventDataParameters.js rename to src/components/pages/reports/event-data/EventDataParameters.js index 8d4dbb62..a01a2972 100644 --- a/components/pages/reports/event-data/EventDataParameters.js +++ b/src/components/pages/reports/event-data/EventDataParameters.js @@ -1,5 +1,5 @@ import { useContext, useRef } from 'react'; -import { useApi, useMessages } from 'hooks'; +import { useApi, useMessages } from 'components/hooks'; import { Form, FormRow, FormButtons, SubmitButton, PopupTrigger, Icon, Popup } from 'react-basics'; import { ReportContext } from 'components/pages/reports/Report'; import Empty from 'components/common/Empty'; diff --git a/components/pages/reports/event-data/EventDataParameters.module.css b/src/components/pages/reports/event-data/EventDataParameters.module.css similarity index 100% rename from components/pages/reports/event-data/EventDataParameters.module.css rename to src/components/pages/reports/event-data/EventDataParameters.module.css diff --git a/components/pages/reports/event-data/EventDataReport.js b/src/components/pages/reports/event-data/EventDataReport.js similarity index 100% rename from components/pages/reports/event-data/EventDataReport.js rename to src/components/pages/reports/event-data/EventDataReport.js diff --git a/components/pages/reports/event-data/EventDataTable.js b/src/components/pages/reports/event-data/EventDataTable.js similarity index 92% rename from components/pages/reports/event-data/EventDataTable.js rename to src/components/pages/reports/event-data/EventDataTable.js index 81b9cad1..b6450261 100644 --- a/components/pages/reports/event-data/EventDataTable.js +++ b/src/components/pages/reports/event-data/EventDataTable.js @@ -1,6 +1,6 @@ import { useContext } from 'react'; import { GridTable, GridColumn } from 'react-basics'; -import { useMessages } from 'hooks'; +import { useMessages } from 'components/hooks'; import { ReportContext } from '../Report'; export function EventDataTable() { diff --git a/components/pages/reports/funnel/FunnelChart.js b/src/components/pages/reports/funnel/FunnelChart.js similarity index 92% rename from components/pages/reports/funnel/FunnelChart.js rename to src/components/pages/reports/funnel/FunnelChart.js index c35afe4e..829a3008 100644 --- a/components/pages/reports/funnel/FunnelChart.js +++ b/src/components/pages/reports/funnel/FunnelChart.js @@ -1,7 +1,7 @@ import { useCallback, useContext, useMemo } from 'react'; import { Loading, StatusLight } from 'react-basics'; -import useMessages from 'hooks/useMessages'; -import useTheme from 'hooks/useTheme'; +import useMessages from 'components/hooks/useMessages'; +import useTheme from 'components/hooks/useTheme'; import BarChart from 'components/metrics/BarChart'; import { formatLongNumber } from 'lib/format'; import styles from './FunnelChart.module.css'; @@ -52,7 +52,7 @@ export function FunnelChart({ className, loading }) { ...colors.chart.visitors, }, ]; - }, [data]); + }, [data, colors, formatMessage, labels]); if (loading) { return ; diff --git a/components/pages/reports/funnel/FunnelChart.module.css b/src/components/pages/reports/funnel/FunnelChart.module.css similarity index 100% rename from components/pages/reports/funnel/FunnelChart.module.css rename to src/components/pages/reports/funnel/FunnelChart.module.css diff --git a/components/pages/reports/funnel/FunnelParameters.js b/src/components/pages/reports/funnel/FunnelParameters.js similarity index 98% rename from components/pages/reports/funnel/FunnelParameters.js rename to src/components/pages/reports/funnel/FunnelParameters.js index 03898db3..2c99a032 100644 --- a/components/pages/reports/funnel/FunnelParameters.js +++ b/src/components/pages/reports/funnel/FunnelParameters.js @@ -1,5 +1,5 @@ import { useContext, useRef } from 'react'; -import { useMessages } from 'hooks'; +import { useMessages } from 'components/hooks'; import { Icon, Form, diff --git a/components/pages/reports/funnel/FunnelReport.js b/src/components/pages/reports/funnel/FunnelReport.js similarity index 100% rename from components/pages/reports/funnel/FunnelReport.js rename to src/components/pages/reports/funnel/FunnelReport.js diff --git a/components/pages/reports/funnel/FunnelReport.module.css b/src/components/pages/reports/funnel/FunnelReport.module.css similarity index 100% rename from components/pages/reports/funnel/FunnelReport.module.css rename to src/components/pages/reports/funnel/FunnelReport.module.css diff --git a/components/pages/reports/funnel/FunnelTable.js b/src/components/pages/reports/funnel/FunnelTable.js similarity index 90% rename from components/pages/reports/funnel/FunnelTable.js rename to src/components/pages/reports/funnel/FunnelTable.js index 9ae8ab58..86e63a5b 100644 --- a/components/pages/reports/funnel/FunnelTable.js +++ b/src/components/pages/reports/funnel/FunnelTable.js @@ -1,6 +1,6 @@ import { useContext } from 'react'; import DataTable from 'components/metrics/DataTable'; -import { useMessages } from 'hooks'; +import { useMessages } from 'components/hooks'; import { ReportContext } from '../Report'; export function FunnelTable() { diff --git a/components/pages/reports/funnel/UrlAddForm.js b/src/components/pages/reports/funnel/UrlAddForm.js similarity index 95% rename from components/pages/reports/funnel/UrlAddForm.js rename to src/components/pages/reports/funnel/UrlAddForm.js index ce202116..3e77ce15 100644 --- a/components/pages/reports/funnel/UrlAddForm.js +++ b/src/components/pages/reports/funnel/UrlAddForm.js @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { useMessages } from 'hooks'; +import { useMessages } from 'components/hooks'; import { Button, Form, FormRow, TextField, Flexbox } from 'react-basics'; import styles from './UrlAddForm.module.css'; diff --git a/components/pages/reports/funnel/UrlAddForm.module.css b/src/components/pages/reports/funnel/UrlAddForm.module.css similarity index 100% rename from components/pages/reports/funnel/UrlAddForm.module.css rename to src/components/pages/reports/funnel/UrlAddForm.module.css diff --git a/components/pages/reports/insights/InsightsParameters.js b/src/components/pages/reports/insights/InsightsParameters.js similarity index 98% rename from components/pages/reports/insights/InsightsParameters.js rename to src/components/pages/reports/insights/InsightsParameters.js index 9f3571e6..db0c1d4e 100644 --- a/components/pages/reports/insights/InsightsParameters.js +++ b/src/components/pages/reports/insights/InsightsParameters.js @@ -1,5 +1,5 @@ import { useContext, useRef } from 'react'; -import { useFormat, useMessages, useFilters } from 'hooks'; +import { useFormat, useMessages, useFilters } from 'components/hooks'; import { Form, FormRow, diff --git a/components/pages/reports/insights/InsightsParameters.module.css b/src/components/pages/reports/insights/InsightsParameters.module.css similarity index 100% rename from components/pages/reports/insights/InsightsParameters.module.css rename to src/components/pages/reports/insights/InsightsParameters.module.css diff --git a/components/pages/reports/insights/InsightsReport.js b/src/components/pages/reports/insights/InsightsReport.js similarity index 100% rename from components/pages/reports/insights/InsightsReport.js rename to src/components/pages/reports/insights/InsightsReport.js diff --git a/components/pages/reports/insights/InsightsTable.js b/src/components/pages/reports/insights/InsightsTable.js similarity index 95% rename from components/pages/reports/insights/InsightsTable.js rename to src/components/pages/reports/insights/InsightsTable.js index d5422c9e..88bd0275 100644 --- a/components/pages/reports/insights/InsightsTable.js +++ b/src/components/pages/reports/insights/InsightsTable.js @@ -1,6 +1,6 @@ import { useContext, useEffect, useState } from 'react'; import { GridTable, GridColumn } from 'react-basics'; -import { useFormat, useMessages } from 'hooks'; +import { useFormat, useMessages } from 'components/hooks'; import { ReportContext } from '../Report'; import EmptyPlaceholder from 'components/common/EmptyPlaceholder'; diff --git a/components/pages/reports/reports.module.css b/src/components/pages/reports/reports.module.css similarity index 100% rename from components/pages/reports/reports.module.css rename to src/components/pages/reports/reports.module.css diff --git a/components/pages/reports/retention/RetentionParameters.js b/src/components/pages/reports/retention/RetentionParameters.js similarity index 96% rename from components/pages/reports/retention/RetentionParameters.js rename to src/components/pages/reports/retention/RetentionParameters.js index d98608ae..aa81cf47 100644 --- a/components/pages/reports/retention/RetentionParameters.js +++ b/src/components/pages/reports/retention/RetentionParameters.js @@ -1,5 +1,5 @@ import { useContext, useRef } from 'react'; -import { useMessages } from 'hooks'; +import { useMessages } from 'components/hooks'; import { Form, FormButtons, FormRow, SubmitButton } from 'react-basics'; import { ReportContext } from 'components/pages/reports/Report'; import { MonthSelect } from 'components/input/MonthSelect'; diff --git a/components/pages/reports/retention/RetentionReport.js b/src/components/pages/reports/retention/RetentionReport.js similarity index 100% rename from components/pages/reports/retention/RetentionReport.js rename to src/components/pages/reports/retention/RetentionReport.js diff --git a/components/pages/reports/retention/RetentionReport.module.css b/src/components/pages/reports/retention/RetentionReport.module.css similarity index 100% rename from components/pages/reports/retention/RetentionReport.module.css rename to src/components/pages/reports/retention/RetentionReport.module.css diff --git a/components/pages/reports/retention/RetentionTable.js b/src/components/pages/reports/retention/RetentionTable.js similarity index 97% rename from components/pages/reports/retention/RetentionTable.js rename to src/components/pages/reports/retention/RetentionTable.js index df0b0f99..09ef2948 100644 --- a/components/pages/reports/retention/RetentionTable.js +++ b/src/components/pages/reports/retention/RetentionTable.js @@ -2,7 +2,7 @@ import { useContext } from 'react'; import classNames from 'classnames'; import { ReportContext } from '../Report'; import EmptyPlaceholder from 'components/common/EmptyPlaceholder'; -import { useMessages } from 'hooks'; +import { useMessages } from 'components/hooks'; import { formatDate } from 'lib/date'; import styles from './RetentionTable.module.css'; diff --git a/components/pages/reports/retention/RetentionTable.module.css b/src/components/pages/reports/retention/RetentionTable.module.css similarity index 100% rename from components/pages/reports/retention/RetentionTable.module.css rename to src/components/pages/reports/retention/RetentionTable.module.css diff --git a/components/pages/settings/profile/DateRangeSetting.js b/src/components/pages/settings/profile/DateRangeSetting.js similarity index 87% rename from components/pages/settings/profile/DateRangeSetting.js rename to src/components/pages/settings/profile/DateRangeSetting.js index 16db3c07..85ad6d79 100644 --- a/components/pages/settings/profile/DateRangeSetting.js +++ b/src/components/pages/settings/profile/DateRangeSetting.js @@ -1,8 +1,8 @@ import DateFilter from 'components/input/DateFilter'; import { Button, Flexbox } from 'react-basics'; -import useDateRange from 'hooks/useDateRange'; +import useDateRange from 'components/hooks/useDateRange'; import { DEFAULT_DATE_RANGE } from 'lib/constants'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export function DateRangeSetting() { const { formatMessage, labels } = useMessages(); diff --git a/components/pages/settings/profile/LanguageSetting.js b/src/components/pages/settings/profile/LanguageSetting.js similarity index 89% rename from components/pages/settings/profile/LanguageSetting.js rename to src/components/pages/settings/profile/LanguageSetting.js index a85e12a2..f1b19626 100644 --- a/components/pages/settings/profile/LanguageSetting.js +++ b/src/components/pages/settings/profile/LanguageSetting.js @@ -1,8 +1,8 @@ import { Button, Dropdown, Item, Flexbox } from 'react-basics'; -import useLocale from 'hooks/useLocale'; +import useLocale from 'components/hooks/useLocale'; import { DEFAULT_LOCALE } from 'lib/constants'; import { languages } from 'lib/lang'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export function LanguageSetting() { const { formatMessage, labels } = useMessages(); diff --git a/components/pages/settings/profile/PasswordChangeButton.js b/src/components/pages/settings/profile/PasswordChangeButton.js similarity index 94% rename from components/pages/settings/profile/PasswordChangeButton.js rename to src/components/pages/settings/profile/PasswordChangeButton.js index 03bf74bc..81324eaa 100644 --- a/components/pages/settings/profile/PasswordChangeButton.js +++ b/src/components/pages/settings/profile/PasswordChangeButton.js @@ -1,7 +1,7 @@ import { Button, Icon, Text, useToasts, ModalTrigger, Modal } from 'react-basics'; import PasswordEditForm from 'components/pages/settings/profile/PasswordEditForm'; import Icons from 'components/icons'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export function PasswordChangeButton() { const { formatMessage, labels, messages } = useMessages(); diff --git a/components/pages/settings/profile/PasswordEditForm.js b/src/components/pages/settings/profile/PasswordEditForm.js similarity index 95% rename from components/pages/settings/profile/PasswordEditForm.js rename to src/components/pages/settings/profile/PasswordEditForm.js index 8e920471..39ecfb77 100644 --- a/components/pages/settings/profile/PasswordEditForm.js +++ b/src/components/pages/settings/profile/PasswordEditForm.js @@ -1,7 +1,7 @@ import { useRef } from 'react'; import { Form, FormRow, FormInput, FormButtons, PasswordField, Button } from 'react-basics'; -import useApi from 'hooks/useApi'; -import useMessages from 'hooks/useMessages'; +import useApi from 'components/hooks/useApi'; +import useMessages from 'components/hooks/useMessages'; export function PasswordEditForm({ onSave, onClose }) { const { formatMessage, labels, messages } = useMessages(); diff --git a/components/pages/settings/profile/ProfileDetails.js b/src/components/pages/settings/profile/ProfileDetails.js similarity index 91% rename from components/pages/settings/profile/ProfileDetails.js rename to src/components/pages/settings/profile/ProfileDetails.js index d1690220..f9dc652b 100644 --- a/components/pages/settings/profile/ProfileDetails.js +++ b/src/components/pages/settings/profile/ProfileDetails.js @@ -4,9 +4,9 @@ import DateRangeSetting from 'components/pages/settings/profile/DateRangeSetting import LanguageSetting from 'components/pages/settings/profile/LanguageSetting'; import ThemeSetting from 'components/pages/settings/profile/ThemeSetting'; import PasswordChangeButton from './PasswordChangeButton'; -import useUser from 'hooks/useUser'; -import useMessages from 'hooks/useMessages'; -import useConfig from 'hooks/useConfig'; +import useUser from 'components/hooks/useUser'; +import useMessages from 'components/hooks/useMessages'; +import useConfig from 'components/hooks/useConfig'; import { ROLES } from 'lib/constants'; export function ProfileDetails() { diff --git a/components/pages/settings/profile/ProfileSettings.js b/src/components/pages/settings/profile/ProfileSettings.js similarity index 87% rename from components/pages/settings/profile/ProfileSettings.js rename to src/components/pages/settings/profile/ProfileSettings.js index 6062dfbf..a217e52c 100644 --- a/components/pages/settings/profile/ProfileSettings.js +++ b/src/components/pages/settings/profile/ProfileSettings.js @@ -1,7 +1,7 @@ import Page from 'components/layout/Page'; import PageHeader from 'components/layout/PageHeader'; import ProfileDetails from './ProfileDetails'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export function ProfileSettings() { const { formatMessage, labels } = useMessages(); diff --git a/components/pages/settings/profile/ThemeSetting.js b/src/components/pages/settings/profile/ThemeSetting.js similarity index 93% rename from components/pages/settings/profile/ThemeSetting.js rename to src/components/pages/settings/profile/ThemeSetting.js index 54a8dac8..aa3a67a2 100644 --- a/components/pages/settings/profile/ThemeSetting.js +++ b/src/components/pages/settings/profile/ThemeSetting.js @@ -1,6 +1,6 @@ import classNames from 'classnames'; import { Button, Icon } from 'react-basics'; -import useTheme from 'hooks/useTheme'; +import useTheme from 'components/hooks/useTheme'; import Sun from 'assets/sun.svg'; import Moon from 'assets/moon.svg'; import styles from './ThemeSetting.module.css'; diff --git a/components/pages/settings/profile/ThemeSetting.module.css b/src/components/pages/settings/profile/ThemeSetting.module.css similarity index 100% rename from components/pages/settings/profile/ThemeSetting.module.css rename to src/components/pages/settings/profile/ThemeSetting.module.css diff --git a/components/pages/settings/profile/TimezoneSetting.js b/src/components/pages/settings/profile/TimezoneSetting.js similarity index 87% rename from components/pages/settings/profile/TimezoneSetting.js rename to src/components/pages/settings/profile/TimezoneSetting.js index 5976f393..fc318081 100644 --- a/components/pages/settings/profile/TimezoneSetting.js +++ b/src/components/pages/settings/profile/TimezoneSetting.js @@ -1,7 +1,7 @@ import { Dropdown, Item, Button, Flexbox } from 'react-basics'; import { listTimeZones } from 'timezone-support'; -import useTimezone from 'hooks/useTimezone'; -import useMessages from 'hooks/useMessages'; +import useTimezone from 'components/hooks/useTimezone'; +import useMessages from 'components/hooks/useMessages'; import { getTimezone } from 'lib/date'; export function TimezoneSetting() { diff --git a/components/pages/settings/teams/TeamAddForm.js b/src/components/pages/settings/teams/TeamAddForm.js similarity index 92% rename from components/pages/settings/teams/TeamAddForm.js rename to src/components/pages/settings/teams/TeamAddForm.js index 8ac36117..7910e098 100644 --- a/components/pages/settings/teams/TeamAddForm.js +++ b/src/components/pages/settings/teams/TeamAddForm.js @@ -8,8 +8,8 @@ import { Button, SubmitButton, } from 'react-basics'; -import useApi from 'hooks/useApi'; -import useMessages from 'hooks/useMessages'; +import useApi from 'components/hooks/useApi'; +import useMessages from 'components/hooks/useMessages'; export function TeamAddForm({ onSave, onClose }) { const { formatMessage, labels } = useMessages(); diff --git a/components/pages/settings/teams/TeamAddWebsiteForm.js b/src/components/pages/settings/teams/TeamAddWebsiteForm.js similarity index 95% rename from components/pages/settings/teams/TeamAddWebsiteForm.js rename to src/components/pages/settings/teams/TeamAddWebsiteForm.js index 4a74de6e..23e3e136 100644 --- a/components/pages/settings/teams/TeamAddWebsiteForm.js +++ b/src/components/pages/settings/teams/TeamAddWebsiteForm.js @@ -1,8 +1,8 @@ -import useApi from 'hooks/useApi'; +import useApi from 'components/hooks/useApi'; import { useRef, useState } from 'react'; import { Button, Dropdown, Form, FormButtons, FormRow, Item, SubmitButton } from 'react-basics'; import WebsiteTags from './WebsiteTags'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export function TeamAddWebsiteForm({ teamId, onSave, onClose }) { const { formatMessage, labels } = useMessages(); diff --git a/components/pages/settings/teams/TeamDeleteForm.js b/src/components/pages/settings/teams/TeamDeleteForm.js similarity index 90% rename from components/pages/settings/teams/TeamDeleteForm.js rename to src/components/pages/settings/teams/TeamDeleteForm.js index 4261aff1..210c8ada 100644 --- a/components/pages/settings/teams/TeamDeleteForm.js +++ b/src/components/pages/settings/teams/TeamDeleteForm.js @@ -1,6 +1,6 @@ import { Button, Form, FormButtons, SubmitButton } from 'react-basics'; -import useApi from 'hooks/useApi'; -import useMessages from 'hooks/useMessages'; +import useApi from 'components/hooks/useApi'; +import useMessages from 'components/hooks/useMessages'; export function TeamDeleteForm({ teamId, teamName, onSave, onClose }) { const { formatMessage, labels, messages, FormattedMessage } = useMessages(); diff --git a/components/pages/settings/teams/TeamEditForm.js b/src/components/pages/settings/teams/TeamEditForm.js similarity index 95% rename from components/pages/settings/teams/TeamEditForm.js rename to src/components/pages/settings/teams/TeamEditForm.js index faeb4e7c..b1dc5854 100644 --- a/components/pages/settings/teams/TeamEditForm.js +++ b/src/components/pages/settings/teams/TeamEditForm.js @@ -10,8 +10,8 @@ import { } from 'react-basics'; import { getRandomChars } from 'next-basics'; import { useRef, useState } from 'react'; -import useApi from 'hooks/useApi'; -import useMessages from 'hooks/useMessages'; +import useApi from 'components/hooks/useApi'; +import useMessages from 'components/hooks/useMessages'; const generateId = () => getRandomChars(16); diff --git a/components/pages/settings/teams/TeamJoinForm.js b/src/components/pages/settings/teams/TeamJoinForm.js similarity index 91% rename from components/pages/settings/teams/TeamJoinForm.js rename to src/components/pages/settings/teams/TeamJoinForm.js index 34153aa1..23abcf00 100644 --- a/components/pages/settings/teams/TeamJoinForm.js +++ b/src/components/pages/settings/teams/TeamJoinForm.js @@ -8,8 +8,8 @@ import { Button, SubmitButton, } from 'react-basics'; -import useApi from 'hooks/useApi'; -import useMessages from 'hooks/useMessages'; +import useApi from 'components/hooks/useApi'; +import useMessages from 'components/hooks/useMessages'; export function TeamJoinForm({ onSave, onClose }) { const { formatMessage, labels, getMessage } = useMessages(); diff --git a/components/pages/settings/teams/TeamLeaveForm.js b/src/components/pages/settings/teams/TeamLeaveForm.js similarity index 90% rename from components/pages/settings/teams/TeamLeaveForm.js rename to src/components/pages/settings/teams/TeamLeaveForm.js index 954006ab..8af2932d 100644 --- a/components/pages/settings/teams/TeamLeaveForm.js +++ b/src/components/pages/settings/teams/TeamLeaveForm.js @@ -1,6 +1,6 @@ import { Button, Form, FormButtons, SubmitButton } from 'react-basics'; -import useApi from 'hooks/useApi'; -import useMessages from 'hooks/useMessages'; +import useApi from 'components/hooks/useApi'; +import useMessages from 'components/hooks/useMessages'; export function TeamLeaveForm({ teamId, userId, teamName, onSave, onClose }) { const { formatMessage, labels, messages, FormattedMessage } = useMessages(); diff --git a/components/pages/settings/teams/TeamMemberRemoveButton.js b/src/components/pages/settings/teams/TeamMemberRemoveButton.js similarity index 74% rename from components/pages/settings/teams/TeamMemberRemoveButton.js rename to src/components/pages/settings/teams/TeamMemberRemoveButton.js index 9f326476..3ec0f8b3 100644 --- a/components/pages/settings/teams/TeamMemberRemoveButton.js +++ b/src/components/pages/settings/teams/TeamMemberRemoveButton.js @@ -1,5 +1,5 @@ -import useApi from 'hooks/useApi'; -import useMessages from 'hooks/useMessages'; +import useApi from 'components/hooks/useApi'; +import useMessages from 'components/hooks/useMessages'; import { Icon, Icons, LoadingButton, Text } from 'react-basics'; export function TeamMemberRemoveButton({ teamId, userId, disabled, onSave }) { @@ -19,7 +19,11 @@ export function TeamMemberRemoveButton({ teamId, userId, disabled, onSave }) { }; return ( - handleRemoveTeamMember()} disabled={disabled} loading={isLoading}> + handleRemoveTeamMember()} + disabled={disabled} + isLoading={isLoading} + > diff --git a/components/pages/settings/teams/TeamMembers.js b/src/components/pages/settings/teams/TeamMembers.js similarity index 86% rename from components/pages/settings/teams/TeamMembers.js rename to src/components/pages/settings/teams/TeamMembers.js index 9762ef29..207ad72d 100644 --- a/components/pages/settings/teams/TeamMembers.js +++ b/src/components/pages/settings/teams/TeamMembers.js @@ -1,8 +1,8 @@ import { Loading, useToasts } from 'react-basics'; import TeamMembersTable from 'components/pages/settings/teams/TeamMembersTable'; -import useApi from 'hooks/useApi'; -import useMessages from 'hooks/useMessages'; -import useApiFilter from 'hooks/useApiFilter'; +import useApi from 'components/hooks/useApi'; +import useMessages from 'components/hooks/useMessages'; +import useApiFilter from 'components/hooks/useApiFilter'; export function TeamMembers({ teamId, readOnly }) { const { showToast } = useToasts(); @@ -33,6 +33,7 @@ export function TeamMembers({ teamId, readOnly }) { <> handleRemoveTeamMember()} loading={isLoading}> + handleRemoveTeamMember()} isLoading={isLoading}> diff --git a/components/pages/settings/teams/TeamWebsites.js b/src/components/pages/settings/teams/TeamWebsites.js similarity index 92% rename from components/pages/settings/teams/TeamWebsites.js rename to src/components/pages/settings/teams/TeamWebsites.js index 2ae344f5..27fe2f85 100644 --- a/components/pages/settings/teams/TeamWebsites.js +++ b/src/components/pages/settings/teams/TeamWebsites.js @@ -11,9 +11,9 @@ import { } from 'react-basics'; import TeamWebsitesTable from 'components/pages/settings/teams/TeamWebsitesTable'; import TeamAddWebsiteForm from 'components/pages/settings/teams/TeamAddWebsiteForm'; -import useApi from 'hooks/useApi'; -import useMessages from 'hooks/useMessages'; -import useApiFilter from 'hooks/useApiFilter'; +import useApi from 'components/hooks/useApi'; +import useMessages from 'components/hooks/useMessages'; +import useApiFilter from 'components/hooks/useApiFilter'; export function TeamWebsites({ teamId }) { const { showToast } = useToasts(); diff --git a/components/pages/settings/teams/TeamWebsitesTable.js b/src/components/pages/settings/teams/TeamWebsitesTable.js similarity index 82% rename from components/pages/settings/teams/TeamWebsitesTable.js rename to src/components/pages/settings/teams/TeamWebsitesTable.js index 564c8a78..5ce08f35 100644 --- a/components/pages/settings/teams/TeamWebsitesTable.js +++ b/src/components/pages/settings/teams/TeamWebsitesTable.js @@ -1,10 +1,9 @@ -import useMessages from 'hooks/useMessages'; -import useUser from 'hooks/useUser'; +import useMessages from 'components/hooks/useMessages'; +import useUser from 'components/hooks/useUser'; import Link from 'next/link'; import { Button, Icon, Icons, Text } from 'react-basics'; import TeamWebsiteRemoveButton from './TeamWebsiteRemoveButton'; import SettingsTable from 'components/common/SettingsTable'; -import useConfig from 'hooks/useConfig'; export function TeamWebsitesTable({ data = [], @@ -13,9 +12,9 @@ export function TeamWebsitesTable({ onFilterChange, onPageChange, onPageSizeChange, + openExternal = false, }) { const { formatMessage, labels } = useMessages(); - const { openExternal } = useConfig(); const { user } = useUser(); const columns = [ @@ -55,11 +54,7 @@ export function TeamWebsitesTable({ {canRemove && ( - + )} ); diff --git a/components/pages/settings/teams/TeamsList.js b/src/components/pages/settings/teams/TeamsList.js similarity index 92% rename from components/pages/settings/teams/TeamsList.js rename to src/components/pages/settings/teams/TeamsList.js index 061100f6..76a87b0c 100644 --- a/components/pages/settings/teams/TeamsList.js +++ b/src/components/pages/settings/teams/TeamsList.js @@ -4,16 +4,16 @@ import Page from 'components/layout/Page'; import PageHeader from 'components/layout/PageHeader'; import TeamAddForm from 'components/pages/settings/teams/TeamAddForm'; import TeamsTable from 'components/pages/settings/teams/TeamsTable'; -import useApi from 'hooks/useApi'; -import useMessages from 'hooks/useMessages'; -import useUser from 'hooks/useUser'; +import useApi from 'components/hooks/useApi'; +import useMessages from 'components/hooks/useMessages'; +import useUser from 'components/hooks/useUser'; import { ROLES } from 'lib/constants'; import { useState } from 'react'; import { Button, Flexbox, Icon, Modal, ModalTrigger, Text, useToasts } from 'react-basics'; import TeamJoinForm from './TeamJoinForm'; -import useApiFilter from 'hooks/useApiFilter'; +import useApiFilter from 'components/hooks/useApiFilter'; -export default function TeamsList() { +export function TeamsList() { const { user } = useUser(); const { formatMessage, labels, messages } = useMessages(); const { filter, page, pageSize, handleFilterChange, handlePageChange, handlePageSizeChange } = @@ -114,3 +114,5 @@ export default function TeamsList() { ); } + +export default TeamsList; diff --git a/components/pages/settings/teams/TeamsTable.js b/src/components/pages/settings/teams/TeamsTable.js similarity index 95% rename from components/pages/settings/teams/TeamsTable.js rename to src/components/pages/settings/teams/TeamsTable.js index e35fb839..e1710783 100644 --- a/components/pages/settings/teams/TeamsTable.js +++ b/src/components/pages/settings/teams/TeamsTable.js @@ -1,7 +1,7 @@ import SettingsTable from 'components/common/SettingsTable'; -import useLocale from 'hooks/useLocale'; -import useMessages from 'hooks/useMessages'; -import useUser from 'hooks/useUser'; +import useLocale from 'components/hooks/useLocale'; +import useMessages from 'components/hooks/useMessages'; +import useUser from 'components/hooks/useUser'; import { ROLES } from 'lib/constants'; import Link from 'next/link'; import { Button, Icon, Icons, Modal, ModalTrigger, Text } from 'react-basics'; diff --git a/components/pages/settings/teams/WebsiteTags.js b/src/components/pages/settings/teams/WebsiteTags.js similarity index 100% rename from components/pages/settings/teams/WebsiteTags.js rename to src/components/pages/settings/teams/WebsiteTags.js diff --git a/components/pages/settings/teams/WebsiteTags.module.css b/src/components/pages/settings/teams/WebsiteTags.module.css similarity index 100% rename from components/pages/settings/teams/WebsiteTags.module.css rename to src/components/pages/settings/teams/WebsiteTags.module.css diff --git a/components/pages/settings/users/UserAddButton.js b/src/components/pages/settings/users/UserAddButton.js similarity index 92% rename from components/pages/settings/users/UserAddButton.js rename to src/components/pages/settings/users/UserAddButton.js index a461f39d..8b691362 100644 --- a/components/pages/settings/users/UserAddButton.js +++ b/src/components/pages/settings/users/UserAddButton.js @@ -1,6 +1,6 @@ import { Button, Icon, Text, Modal, Icons, ModalTrigger } from 'react-basics'; import UserAddForm from './UserAddForm'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export function UserAddButton({ onSave }) { const { formatMessage, labels } = useMessages(); diff --git a/components/pages/settings/users/UserAddForm.js b/src/components/pages/settings/users/UserAddForm.js similarity index 95% rename from components/pages/settings/users/UserAddForm.js rename to src/components/pages/settings/users/UserAddForm.js index bb408749..38c1bedd 100644 --- a/components/pages/settings/users/UserAddForm.js +++ b/src/components/pages/settings/users/UserAddForm.js @@ -10,9 +10,9 @@ import { SubmitButton, Button, } from 'react-basics'; -import useApi from 'hooks/useApi'; +import useApi from 'components/hooks/useApi'; import { ROLES } from 'lib/constants'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export function UserAddForm({ onSave, onClose }) { const { post, useMutation } = useApi(); diff --git a/components/pages/settings/users/UserDeleteForm.js b/src/components/pages/settings/users/UserDeleteForm.js similarity index 91% rename from components/pages/settings/users/UserDeleteForm.js rename to src/components/pages/settings/users/UserDeleteForm.js index bd412e44..5a47fdc1 100644 --- a/components/pages/settings/users/UserDeleteForm.js +++ b/src/components/pages/settings/users/UserDeleteForm.js @@ -1,7 +1,7 @@ import { useMutation } from '@tanstack/react-query'; import { Button, Form, FormButtons, SubmitButton } from 'react-basics'; -import useApi from 'hooks/useApi'; -import useMessages from 'hooks/useMessages'; +import useApi from 'components/hooks/useApi'; +import useMessages from 'components/hooks/useMessages'; export function UserDeleteForm({ userId, username, onSave, onClose }) { const { formatMessage, FormattedMessage, labels, messages } = useMessages(); diff --git a/components/pages/settings/users/UserEditForm.js b/src/components/pages/settings/users/UserEditForm.js similarity index 95% rename from components/pages/settings/users/UserEditForm.js rename to src/components/pages/settings/users/UserEditForm.js index 887531e8..157c9ad6 100644 --- a/components/pages/settings/users/UserEditForm.js +++ b/src/components/pages/settings/users/UserEditForm.js @@ -9,9 +9,9 @@ import { SubmitButton, PasswordField, } from 'react-basics'; -import useApi from 'hooks/useApi'; +import useApi from 'components/hooks/useApi'; import { ROLES } from 'lib/constants'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export function UserEditForm({ userId, data, onSave }) { const { formatMessage, labels, messages } = useMessages(); diff --git a/components/pages/settings/users/UserSettings.js b/src/components/pages/settings/users/UserSettings.js similarity index 91% rename from components/pages/settings/users/UserSettings.js rename to src/components/pages/settings/users/UserSettings.js index d703e964..596e09f0 100644 --- a/components/pages/settings/users/UserSettings.js +++ b/src/components/pages/settings/users/UserSettings.js @@ -1,12 +1,12 @@ import { useEffect, useState } from 'react'; import { Breadcrumbs, Item, Tabs, useToasts } from 'react-basics'; import Link from 'next/link'; -import UserEditForm from 'components/pages/settings/users//UserEditForm'; +import UserEditForm from 'components/pages/settings/users/UserEditForm'; import Page from 'components/layout/Page'; import PageHeader from 'components/layout/PageHeader'; -import useApi from 'hooks/useApi'; +import useApi from 'components/hooks/useApi'; import UserWebsites from './UserWebsites'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export function UserSettings({ userId }) { const { formatMessage, labels, messages } = useMessages(); diff --git a/src/components/pages/settings/users/UserWebsites.js b/src/components/pages/settings/users/UserWebsites.js new file mode 100644 index 00000000..14127275 --- /dev/null +++ b/src/components/pages/settings/users/UserWebsites.js @@ -0,0 +1,36 @@ +import Page from 'components/layout/Page'; +import useApi from 'components/hooks/useApi'; +import WebsitesTable from 'components/pages/settings/websites/WebsitesTable'; +import useApiFilter from 'components/hooks/useApiFilter'; + +export function UserWebsites({ userId }) { + const { filter, page, pageSize, handleFilterChange, handlePageChange, handlePageSizeChange } = + useApiFilter(); + const { get, useQuery } = useApi(); + const { data, isLoading, error } = useQuery( + ['user:websites', userId, filter, page, pageSize], + () => + get(`/users/${userId}/websites`, { + filter, + page, + pageSize, + }), + ); + const hasData = data && data.length !== 0; + + return ( + + {hasData && ( + + )} + + ); +} + +export default UserWebsites; diff --git a/components/pages/settings/users/UsersList.js b/src/components/pages/settings/users/UsersList.js similarity index 90% rename from components/pages/settings/users/UsersList.js rename to src/components/pages/settings/users/UsersList.js index 614aabef..0bc8612e 100644 --- a/components/pages/settings/users/UsersList.js +++ b/src/components/pages/settings/users/UsersList.js @@ -4,10 +4,10 @@ import PageHeader from 'components/layout/PageHeader'; import EmptyPlaceholder from 'components/common/EmptyPlaceholder'; import UsersTable from './UsersTable'; import UserAddButton from './UserAddButton'; -import useApi from 'hooks/useApi'; -import useUser from 'hooks/useUser'; -import useMessages from 'hooks/useMessages'; -import useApiFilter from 'hooks/useApiFilter'; +import useApi from 'components/hooks/useApi'; +import useUser from 'components/hooks/useUser'; +import useMessages from 'components/hooks/useMessages'; +import useApiFilter from 'components/hooks/useApiFilter'; export function UsersList() { const { formatMessage, labels, messages } = useMessages(); diff --git a/components/pages/settings/users/UsersTable.js b/src/components/pages/settings/users/UsersTable.js similarity index 93% rename from components/pages/settings/users/UsersTable.js rename to src/components/pages/settings/users/UsersTable.js index f4c9dd77..1a93710d 100644 --- a/components/pages/settings/users/UsersTable.js +++ b/src/components/pages/settings/users/UsersTable.js @@ -1,12 +1,12 @@ import { Button, Text, Icon, Icons, ModalTrigger, Modal } from 'react-basics'; import { formatDistance } from 'date-fns'; import Link from 'next/link'; -import useUser from 'hooks/useUser'; +import useUser from 'components/hooks/useUser'; import UserDeleteForm from './UserDeleteForm'; import { ROLES } from 'lib/constants'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; import SettingsTable from 'components/common/SettingsTable'; -import useLocale from 'hooks/useLocale'; +import useLocale from 'components/hooks/useLocale'; export function UsersTable({ data = { data: [] }, @@ -54,7 +54,7 @@ export function UsersTable({ onPageSizeChange={onPageSizeChange} filterValue={filterValue} > - {(row, keys, rowIndex) => { + {row => { return ( <> diff --git a/components/pages/settings/websites/ShareUrl.js b/src/components/pages/settings/websites/ShareUrl.js similarity index 94% rename from components/pages/settings/websites/ShareUrl.js rename to src/components/pages/settings/websites/ShareUrl.js index 7f0b352c..a7b7fc2f 100644 --- a/components/pages/settings/websites/ShareUrl.js +++ b/src/components/pages/settings/websites/ShareUrl.js @@ -11,8 +11,8 @@ import { import { useEffect, useMemo, useRef, useState } from 'react'; import { getRandomChars } from 'next-basics'; import { useRouter } from 'next/router'; -import useApi from 'hooks/useApi'; -import useMessages from 'hooks/useMessages'; +import useApi from 'components/hooks/useApi'; +import useMessages from 'components/hooks/useMessages'; const generateId = () => getRandomChars(16); @@ -31,7 +31,7 @@ export function ShareUrl({ websiteId, data, onSave }) { `${process.env.analyticsUrl || location.origin}${basePath}/share/${id}/${encodeURIComponent( name, )}`, - [id, name], + [id, name, basePath], ); const handleSubmit = async data => { diff --git a/components/pages/settings/websites/TrackingCode.js b/src/components/pages/settings/websites/TrackingCode.js similarity index 85% rename from components/pages/settings/websites/TrackingCode.js rename to src/components/pages/settings/websites/TrackingCode.js index c847ed0d..5159ff91 100644 --- a/components/pages/settings/websites/TrackingCode.js +++ b/src/components/pages/settings/websites/TrackingCode.js @@ -1,6 +1,6 @@ import { TextArea } from 'react-basics'; -import useMessages from 'hooks/useMessages'; -import useConfig from 'hooks/useConfig'; +import useMessages from 'components/hooks/useMessages'; +import useConfig from 'components/hooks/useConfig'; export function TrackingCode({ websiteId }) { const { formatMessage, messages } = useMessages(); diff --git a/components/pages/settings/websites/WebsiteAddForm.js b/src/components/pages/settings/websites/WebsiteAddForm.js similarity index 93% rename from components/pages/settings/websites/WebsiteAddForm.js rename to src/components/pages/settings/websites/WebsiteAddForm.js index 77b850b4..371343ba 100644 --- a/components/pages/settings/websites/WebsiteAddForm.js +++ b/src/components/pages/settings/websites/WebsiteAddForm.js @@ -7,9 +7,9 @@ import { Button, SubmitButton, } from 'react-basics'; -import useApi from 'hooks/useApi'; +import useApi from 'components/hooks/useApi'; import { DOMAIN_REGEX } from 'lib/constants'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export function WebsiteAddForm({ onSave, onClose }) { const { formatMessage, labels, messages } = useMessages(); diff --git a/components/pages/settings/websites/WebsiteData.js b/src/components/pages/settings/websites/WebsiteData.js similarity index 96% rename from components/pages/settings/websites/WebsiteData.js rename to src/components/pages/settings/websites/WebsiteData.js index a2bc6bfa..08d6702e 100644 --- a/components/pages/settings/websites/WebsiteData.js +++ b/src/components/pages/settings/websites/WebsiteData.js @@ -1,7 +1,7 @@ import { Button, Modal, ModalTrigger, ActionForm } from 'react-basics'; import WebsiteDeleteForm from 'components/pages/settings/websites/WebsiteDeleteForm'; import WebsiteResetForm from 'components/pages/settings/websites/WebsiteResetForm'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export function WebsiteData({ websiteId, onSave }) { const { formatMessage, labels, messages } = useMessages(); diff --git a/components/pages/settings/websites/WebsiteDeleteForm.js b/src/components/pages/settings/websites/WebsiteDeleteForm.js similarity index 92% rename from components/pages/settings/websites/WebsiteDeleteForm.js rename to src/components/pages/settings/websites/WebsiteDeleteForm.js index c9e302fc..1548bddb 100644 --- a/components/pages/settings/websites/WebsiteDeleteForm.js +++ b/src/components/pages/settings/websites/WebsiteDeleteForm.js @@ -7,8 +7,8 @@ import { SubmitButton, TextField, } from 'react-basics'; -import useApi from 'hooks/useApi'; -import useMessages from 'hooks/useMessages'; +import useApi from 'components/hooks/useApi'; +import useMessages from 'components/hooks/useMessages'; const CONFIRM_VALUE = 'DELETE'; diff --git a/components/pages/settings/websites/WebsiteEditForm.js b/src/components/pages/settings/websites/WebsiteEditForm.js similarity index 94% rename from components/pages/settings/websites/WebsiteEditForm.js rename to src/components/pages/settings/websites/WebsiteEditForm.js index 89c62889..18ad0ac9 100644 --- a/components/pages/settings/websites/WebsiteEditForm.js +++ b/src/components/pages/settings/websites/WebsiteEditForm.js @@ -1,8 +1,8 @@ import { SubmitButton, Form, FormInput, FormRow, FormButtons, TextField } from 'react-basics'; import { useRef } from 'react'; -import useApi from 'hooks/useApi'; +import useApi from 'components/hooks/useApi'; import { DOMAIN_REGEX } from 'lib/constants'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export function WebsiteEditForm({ websiteId, data, onSave }) { const { formatMessage, labels, messages } = useMessages(); diff --git a/components/pages/settings/websites/WebsiteResetForm.js b/src/components/pages/settings/websites/WebsiteResetForm.js similarity index 92% rename from components/pages/settings/websites/WebsiteResetForm.js rename to src/components/pages/settings/websites/WebsiteResetForm.js index 5fc0acf7..9886429b 100644 --- a/components/pages/settings/websites/WebsiteResetForm.js +++ b/src/components/pages/settings/websites/WebsiteResetForm.js @@ -7,8 +7,8 @@ import { SubmitButton, TextField, } from 'react-basics'; -import useApi from 'hooks/useApi'; -import useMessages from 'hooks/useMessages'; +import useApi from 'components/hooks/useApi'; +import useMessages from 'components/hooks/useMessages'; const CONFIRM_VALUE = 'RESET'; diff --git a/components/pages/settings/websites/WebsiteSettings.js b/src/components/pages/settings/websites/WebsiteSettings.js similarity index 93% rename from components/pages/settings/websites/WebsiteSettings.js rename to src/components/pages/settings/websites/WebsiteSettings.js index 5a96fa8c..ac8cd87c 100644 --- a/components/pages/settings/websites/WebsiteSettings.js +++ b/src/components/pages/settings/websites/WebsiteSettings.js @@ -8,14 +8,12 @@ import WebsiteEditForm from 'components/pages/settings/websites/WebsiteEditForm' import WebsiteData from 'components/pages/settings/websites/WebsiteData'; import TrackingCode from 'components/pages/settings/websites/TrackingCode'; import ShareUrl from 'components/pages/settings/websites/ShareUrl'; -import useApi from 'hooks/useApi'; -import useMessages from 'hooks/useMessages'; -import useConfig from 'hooks/useConfig'; +import useApi from 'components/hooks/useApi'; +import useMessages from 'components/hooks/useMessages'; -export function WebsiteSettings({ websiteId }) { +export function WebsiteSettings({ websiteId, openExternal = false }) { const router = useRouter(); const { formatMessage, labels, messages } = useMessages(); - const { openExternal } = useConfig(); const { get, useQuery } = useApi(); const { showToast } = useToasts(); const { data, isLoading } = useQuery( diff --git a/components/pages/settings/websites/WebsitesList.js b/src/components/pages/settings/websites/WebsitesList.js similarity index 91% rename from components/pages/settings/websites/WebsitesList.js rename to src/components/pages/settings/websites/WebsitesList.js index f1a2eb0f..0cec3832 100644 --- a/components/pages/settings/websites/WebsitesList.js +++ b/src/components/pages/settings/websites/WebsitesList.js @@ -2,10 +2,10 @@ import Page from 'components/layout/Page'; import PageHeader from 'components/layout/PageHeader'; import WebsiteAddForm from 'components/pages/settings/websites/WebsiteAddForm'; import WebsitesTable from 'components/pages/settings/websites/WebsitesTable'; -import useApi from 'hooks/useApi'; -import useApiFilter from 'hooks/useApiFilter'; -import useMessages from 'hooks/useMessages'; -import useUser from 'hooks/useUser'; +import useApi from 'components/hooks/useApi'; +import useApiFilter from 'components/hooks/useApiFilter'; +import useMessages from 'components/hooks/useMessages'; +import useUser from 'components/hooks/useUser'; import { ROLES } from 'lib/constants'; import { Button, Icon, Icons, Modal, ModalTrigger, Text, useToasts } from 'react-basics'; diff --git a/components/pages/settings/websites/WebsitesTable.js b/src/components/pages/settings/websites/WebsitesTable.js similarity index 83% rename from components/pages/settings/websites/WebsitesTable.js rename to src/components/pages/settings/websites/WebsitesTable.js index 08c906aa..7fa50716 100644 --- a/components/pages/settings/websites/WebsitesTable.js +++ b/src/components/pages/settings/websites/WebsitesTable.js @@ -1,10 +1,9 @@ -import EmptyPlaceholder from 'components/common/EmptyPlaceholder'; import Link from 'next/link'; import { Button, Text, Icon, Icons } from 'react-basics'; import SettingsTable from 'components/common/SettingsTable'; -import useMessages from 'hooks/useMessages'; -import useConfig from 'hooks/useConfig'; -import useUser from 'hooks/useUser'; +import Empty from 'components/common/Empty'; +import useMessages from 'components/hooks/useMessages'; +import useUser from 'components/hooks/useUser'; export function WebsitesTable({ data = [], @@ -14,12 +13,12 @@ export function WebsitesTable({ onPageSizeChange, showTeam, showEditButton, + openExternal = false, }) { - const { formatMessage, labels, messages } = useMessages(); - const { openExternal } = useConfig(); + const { formatMessage, labels } = useMessages(); const { user } = useUser(); - const showTable = data && (filterValue || data?.data.length !== 0); + const showTable = data && (filterValue || data?.data?.length !== 0); const teamColumns = [ { name: 'teamName', label: formatMessage(labels.teamName) }, @@ -82,7 +81,7 @@ export function WebsitesTable({ }} )} - {!showTable && } + {!showTable && } ); } diff --git a/components/pages/settings/websites/WebsitesTable.module.css b/src/components/pages/settings/websites/WebsitesTable.module.css similarity index 100% rename from components/pages/settings/websites/WebsitesTable.module.css rename to src/components/pages/settings/websites/WebsitesTable.module.css diff --git a/components/pages/websites/WebsiteChart.js b/src/components/pages/websites/WebsiteChart.js similarity index 98% rename from components/pages/websites/WebsiteChart.js rename to src/components/pages/websites/WebsiteChart.js index fac0fb37..7e20e785 100644 --- a/components/pages/websites/WebsiteChart.js +++ b/src/components/pages/websites/WebsiteChart.js @@ -1,6 +1,6 @@ import { useMemo } from 'react'; import PageviewsChart from 'components/metrics/PageviewsChart'; -import { useApi, useDateRange, useTimezone, usePageQuery } from 'hooks'; +import { useApi, useDateRange, useTimezone, usePageQuery } from 'components/hooks'; import { getDateArray } from 'lib/date'; export function WebsiteChart({ websiteId }) { diff --git a/components/pages/websites/WebsiteChart.module.css b/src/components/pages/websites/WebsiteChart.module.css similarity index 100% rename from components/pages/websites/WebsiteChart.module.css rename to src/components/pages/websites/WebsiteChart.module.css diff --git a/components/pages/websites/WebsiteChartList.js b/src/components/pages/websites/WebsiteChartList.js similarity index 92% rename from components/pages/websites/WebsiteChartList.js rename to src/components/pages/websites/WebsiteChartList.js index 62b05a4d..56cbe157 100644 --- a/components/pages/websites/WebsiteChartList.js +++ b/src/components/pages/websites/WebsiteChartList.js @@ -7,7 +7,7 @@ import useDashboard from 'store/dashboard'; import styles from './WebsiteList.module.css'; import WebsiteHeader from './WebsiteHeader'; import { WebsiteMetricsBar } from './WebsiteMetricsBar'; -import { useMessages, useLocale } from 'hooks'; +import { useMessages, useLocale } from 'components/hooks'; import Icons from 'components/icons'; export default function WebsiteChartList({ websites, showCharts, limit }) { @@ -40,7 +40,7 @@ export default function WebsiteChartList({ websites, showCharts, limit }) { - + {showCharts && }
) : null; diff --git a/components/pages/websites/WebsiteDetailsPage.js b/src/components/pages/websites/WebsiteDetailsPage.js similarity index 93% rename from components/pages/websites/WebsiteDetailsPage.js rename to src/components/pages/websites/WebsiteDetailsPage.js index 9e0519b2..c5ac4775 100644 --- a/components/pages/websites/WebsiteDetailsPage.js +++ b/src/components/pages/websites/WebsiteDetailsPage.js @@ -3,10 +3,10 @@ import { useRouter } from 'next/router'; import Page from 'components/layout/Page'; import WebsiteChart from 'components/pages/websites/WebsiteChart'; import FilterTags from 'components/metrics/FilterTags'; -import usePageQuery from 'hooks/usePageQuery'; +import usePageQuery from 'components/hooks/usePageQuery'; import WebsiteTableView from './WebsiteTableView'; import WebsiteMenuView from './WebsiteMenuView'; -import { useWebsite } from 'hooks'; +import { useWebsite } from 'components/hooks'; import WebsiteHeader from './WebsiteHeader'; import { WebsiteMetricsBar } from './WebsiteMetricsBar'; diff --git a/components/pages/websites/WebsiteEventData.js b/src/components/pages/websites/WebsiteEventData.js similarity index 94% rename from components/pages/websites/WebsiteEventData.js rename to src/components/pages/websites/WebsiteEventData.js index 7f9a6829..ea8e473b 100644 --- a/components/pages/websites/WebsiteEventData.js +++ b/src/components/pages/websites/WebsiteEventData.js @@ -2,7 +2,7 @@ import { Flexbox } from 'react-basics'; import EventDataTable from 'components/pages/event-data/EventDataTable'; import EventDataValueTable from 'components/pages/event-data/EventDataValueTable'; import { EventDataMetricsBar } from 'components/pages/event-data/EventDataMetricsBar'; -import { useDateRange, useApi, usePageQuery } from 'hooks'; +import { useDateRange, useApi, usePageQuery } from 'components/hooks'; import styles from './WebsiteEventData.module.css'; function useData(websiteId, event) { diff --git a/components/pages/websites/WebsiteEventData.module.css b/src/components/pages/websites/WebsiteEventData.module.css similarity index 100% rename from components/pages/websites/WebsiteEventData.module.css rename to src/components/pages/websites/WebsiteEventData.module.css diff --git a/components/pages/websites/WebsiteEventDataPage.js b/src/components/pages/websites/WebsiteEventDataPage.js similarity index 100% rename from components/pages/websites/WebsiteEventDataPage.js rename to src/components/pages/websites/WebsiteEventDataPage.js diff --git a/components/pages/websites/WebsiteHeader.js b/src/components/pages/websites/WebsiteHeader.js similarity index 94% rename from components/pages/websites/WebsiteHeader.js rename to src/components/pages/websites/WebsiteHeader.js index 0790397f..fb4e0986 100644 --- a/components/pages/websites/WebsiteHeader.js +++ b/src/components/pages/websites/WebsiteHeader.js @@ -1,11 +1,11 @@ import classNames from 'classnames'; -import { Flexbox, Row, Column, Text, Button, Icon } from 'react-basics'; +import { Row, Column, Text, Button, Icon } from 'react-basics'; import Link from 'next/link'; import { useRouter } from 'next/router'; import Favicon from 'components/common/Favicon'; import ActiveUsers from 'components/metrics/ActiveUsers'; import Icons from 'components/icons'; -import { useMessages, useWebsite } from 'hooks'; +import { useMessages, useWebsite } from 'components/hooks'; import styles from './WebsiteHeader.module.css'; export function WebsiteHeader({ websiteId, showLinks = true, children }) { diff --git a/components/pages/websites/WebsiteHeader.module.css b/src/components/pages/websites/WebsiteHeader.module.css similarity index 100% rename from components/pages/websites/WebsiteHeader.module.css rename to src/components/pages/websites/WebsiteHeader.module.css diff --git a/components/pages/websites/WebsiteList.module.css b/src/components/pages/websites/WebsiteList.module.css similarity index 100% rename from components/pages/websites/WebsiteList.module.css rename to src/components/pages/websites/WebsiteList.module.css diff --git a/components/pages/websites/WebsiteMenuView.js b/src/components/pages/websites/WebsiteMenuView.js similarity index 96% rename from components/pages/websites/WebsiteMenuView.js rename to src/components/pages/websites/WebsiteMenuView.js index 39adb188..8c74d615 100644 --- a/components/pages/websites/WebsiteMenuView.js +++ b/src/components/pages/websites/WebsiteMenuView.js @@ -15,10 +15,10 @@ import ScreenTable from 'components/metrics/ScreenTable'; import EventsTable from 'components/metrics/EventsTable'; import Icons from 'components/icons'; import SideNav from 'components/layout/SideNav'; -import usePageQuery from 'hooks/usePageQuery'; -import useMessages from 'hooks/useMessages'; +import usePageQuery from 'components/hooks/usePageQuery'; +import useMessages from 'components/hooks/useMessages'; import styles from './WebsiteMenuView.module.css'; -import useLocale from 'hooks/useLocale'; +import useLocale from 'components/hooks/useLocale'; const views = { url: PagesTable, diff --git a/components/pages/websites/WebsiteMenuView.module.css b/src/components/pages/websites/WebsiteMenuView.module.css similarity index 100% rename from components/pages/websites/WebsiteMenuView.module.css rename to src/components/pages/websites/WebsiteMenuView.module.css diff --git a/components/pages/websites/WebsiteMetricsBar.js b/src/components/pages/websites/WebsiteMetricsBar.js similarity index 65% rename from components/pages/websites/WebsiteMetricsBar.js rename to src/components/pages/websites/WebsiteMetricsBar.js index 3683310c..35605804 100644 --- a/components/pages/websites/WebsiteMetricsBar.js +++ b/src/components/pages/websites/WebsiteMetricsBar.js @@ -1,20 +1,25 @@ import classNames from 'classnames'; -import { Row, Column } from 'react-basics'; -import { formatShortTime } from 'lib/format'; -import MetricCard from 'components/metrics/MetricCard'; +import { useApi, useDateRange, useMessages, usePageQuery, useSticky } from 'components/hooks'; import RefreshButton from 'components/input/RefreshButton'; import WebsiteDateFilter from 'components/input/WebsiteDateFilter'; +import MetricCard from 'components/metrics/MetricCard'; import MetricsBar from 'components/metrics/MetricsBar'; -import { useApi, useDateRange, usePageQuery, useMessages, useSticky } from 'hooks'; +import FilterSelectForm from 'components/pages/reports/FilterSelectForm'; +import PopupForm from 'components/pages/reports/PopupForm'; +import { formatShortTime } from 'lib/format'; +import { Button, Column, Icon, Icons, Popup, PopupTrigger, Row, TooltipPopup } from 'react-basics'; import styles from './WebsiteMetricsBar.module.css'; -export function WebsiteMetricsBar({ websiteId, sticky }) { +export function WebsiteMetricsBar({ websiteId, showFilter = true, sticky }) { const { formatMessage, labels } = useMessages(); + const { get, useQuery } = useApi(); const [dateRange] = useDateRange(websiteId); const { startDate, endDate, modified } = dateRange; const { ref, isSticky } = useSticky({ enabled: sticky }); const { + resolveUrl, + router, query: { url, referrer, title, os, browser, device, country, region, city }, } = usePageQuery(); @@ -39,6 +44,17 @@ export function WebsiteMetricsBar({ websiteId, sticky }) { }), ); + const fieldOptions = [ + { name: 'url', type: 'string', label: formatMessage(labels.url) }, + { name: 'referrer', type: 'string', label: formatMessage(labels.referrer) }, + { name: 'browser', type: 'string', label: formatMessage(labels.browser) }, + { name: 'os', type: 'string', label: formatMessage(labels.os) }, + { name: 'device', type: 'string', label: formatMessage(labels.device) }, + { name: 'country', type: 'string', label: formatMessage(labels.country) }, + { name: 'region', type: 'string', label: formatMessage(labels.region) }, + { name: 'city', type: 'string', label: formatMessage(labels.city) }, + ]; + const { pageviews, uniques, bounces, totaltime } = data || {}; const num = Math.min(data && uniques.value, data && bounces.value); const diffs = data && { @@ -48,6 +64,42 @@ export function WebsiteMetricsBar({ websiteId, sticky }) { totaltime: totaltime.value - totaltime.change, }; + const handleAddFilter = ({ name, value }) => { + router.push(resolveUrl({ [name]: value })); + }; + + const WebsiteFilterButton = () => { + return ( + + + + + + {close => { + return ( + + { + handleAddFilter(value); + close(); + }} + includeOnlyEquals={true} + /> + + ); + }} + + + ); + }; + return (
- + {showFilter && } +
diff --git a/components/pages/websites/WebsiteMetricsBar.module.css b/src/components/pages/websites/WebsiteMetricsBar.module.css similarity index 100% rename from components/pages/websites/WebsiteMetricsBar.module.css rename to src/components/pages/websites/WebsiteMetricsBar.module.css diff --git a/components/pages/websites/WebsiteReportsPage.js b/src/components/pages/websites/WebsiteReportsPage.js similarity index 83% rename from components/pages/websites/WebsiteReportsPage.js rename to src/components/pages/websites/WebsiteReportsPage.js index b04c50d1..40631839 100644 --- a/components/pages/websites/WebsiteReportsPage.js +++ b/src/components/pages/websites/WebsiteReportsPage.js @@ -1,13 +1,13 @@ -import EmptyPlaceholder from 'components/common/EmptyPlaceholder'; import Page from 'components/layout/Page'; +import Empty from 'components/common/Empty'; import ReportsTable from 'components/pages/reports/ReportsTable'; -import { useMessages, useWebsiteReports } from 'hooks'; +import { useMessages, useWebsiteReports } from 'components/hooks'; import Link from 'next/link'; import { Button, Flexbox, Icon, Icons, Text } from 'react-basics'; import WebsiteHeader from './WebsiteHeader'; export function WebsiteReportsPage({ websiteId }) { - const { formatMessage, labels, messages } = useMessages(); + const { formatMessage, labels } = useMessages(); const { reports, error, @@ -48,7 +48,7 @@ export function WebsiteReportsPage({ websiteId }) { filterValue={filter} /> )} - {!hasData && } + {!hasData && }
); } diff --git a/components/pages/websites/WebsiteTableView.js b/src/components/pages/websites/WebsiteTableView.js similarity index 100% rename from components/pages/websites/WebsiteTableView.js rename to src/components/pages/websites/WebsiteTableView.js diff --git a/components/pages/websites/WebsiteTableView.module.css b/src/components/pages/websites/WebsiteTableView.module.css similarity index 100% rename from components/pages/websites/WebsiteTableView.module.css rename to src/components/pages/websites/WebsiteTableView.module.css diff --git a/components/pages/websites/WebsitesPage.js b/src/components/pages/websites/WebsitesPage.js similarity index 93% rename from components/pages/websites/WebsitesPage.js rename to src/components/pages/websites/WebsitesPage.js index fafc62af..2eb060d3 100644 --- a/components/pages/websites/WebsitesPage.js +++ b/src/components/pages/websites/WebsitesPage.js @@ -2,9 +2,9 @@ import Page from 'components/layout/Page'; import PageHeader from 'components/layout/PageHeader'; import WebsiteAddForm from 'components/pages/settings/websites/WebsiteAddForm'; import WebsiteList from 'components/pages/settings/websites/WebsitesList'; -import { useMessages } from 'hooks'; -import useUser from 'hooks/useUser'; -import useConfig from 'hooks/useConfig'; +import { useMessages } from 'components/hooks'; +import useUser from 'components/hooks/useUser'; +import useConfig from 'components/hooks/useConfig'; import { ROLES } from 'lib/constants'; import { useState } from 'react'; import { diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 00000000..f2ef13ca --- /dev/null +++ b/src/index.ts @@ -0,0 +1,117 @@ +/* +export * from 'components/common/ConfirmDeleteForm'; +export * from 'components/common/Empty'; +export * from 'components/common/EmptyPlaceholder'; +export * from 'components/common/ErrorBoundary'; +export * from 'components/common/ErrorMessage'; +export * from 'components/common/Favicon'; +export * from 'components/common/FilterButtons'; +export * from 'components/common/FilterLink'; +export * from 'components/common/HamburgerButton'; +export * from 'components/common/HoverTooltip'; +export * from 'components/common/LinkButton'; +export * from 'components/common/MobileMenu'; +export * from 'components/common/Pager'; +export * from 'components/common/SettingsTable'; +export * from 'components/common/UpdateNotice'; +export * from 'components/common/WorldMap'; + +export * from 'components/hooks/useApi'; +export * from 'components/hooks/useConfig'; +export * from 'components/hooks/useCountryNames'; +export * from 'components/hooks/useDateRange'; +export * from 'components/hooks/useDocumentClick'; +export * from 'components/hooks/useEscapeKey'; +export * from 'components/hooks/useFilters'; +export * from 'components/hooks/useForceUpdate'; +export * from 'components/hooks/useFormat'; +export * from 'components/hooks/useLanguageNames'; +export * from 'components/hooks/useLocale'; +export * from 'components/hooks/useMessages'; +export * from 'components/hooks/usePageQuery'; +export * from 'components/hooks/useReport'; +export * from 'components/hooks/useReports'; +export * from 'components/hooks/useRequireLogin'; +export * from 'components/hooks/useShareToken'; +export * from 'components/hooks/useSticky'; +export * from 'components/hooks/useTheme'; +export * from 'components/hooks/useTimezone'; +export * from 'components/hooks/useUser'; +export * from 'components/hooks/useWebsite'; +export * from 'components/hooks/useWebsiteReports'; + +export * from 'components/input/DateFilter'; +export * from 'components/input/LanguageButton'; +export * from 'components/input/LogoutButton'; +export * from 'components/input/MonthSelect'; +export * from 'components/input/ProfileButton'; +export * from 'components/input/RefreshButton'; +export * from 'components/input/SettingsButton'; +export * from 'components/input/ThemeButton'; +export * from 'components/input/WebsiteDateFilter'; +export * from 'components/input/WebsiteSelect'; + +export * from 'components/layout/AppLayout'; +export * from 'components/layout/Footer'; +export * from 'components/layout/Grid'; +export * from 'components/layout/Header'; +export * from 'components/layout/NavBar'; +export * from 'components/layout/NavGroup'; +export * from 'components/layout/Page'; +export * from 'components/layout/PageHeader'; +export * from 'components/layout/ReportsLayout'; +export * from 'components/layout/SettingsLayout'; +export * from 'components/layout/ShareLayout'; +export * from 'components/layout/SideNav'; +*/ + +export * from 'components/hooks/useApi'; +export * from 'components/hooks/useConfig'; +export * from 'components/hooks/useCountryNames'; +export * from 'components/hooks/useDateRange'; +export * from 'components/hooks/useDocumentClick'; +export * from 'components/hooks/useEscapeKey'; +export * from 'components/hooks/useFilters'; +export * from 'components/hooks/useForceUpdate'; +export * from 'components/hooks/useFormat'; +export * from 'components/hooks/useLanguageNames'; +export * from 'components/hooks/useLocale'; +export * from 'components/hooks/useMessages'; +export * from 'components/hooks/usePageQuery'; +export * from 'components/hooks/useReport'; +export * from 'components/hooks/useReports'; +export * from 'components/hooks/useRequireLogin'; +export * from 'components/hooks/useShareToken'; +export * from 'components/hooks/useSticky'; +export * from 'components/hooks/useTheme'; +export * from 'components/hooks/useTimezone'; +export * from 'components/hooks/useUser'; +export * from 'components/hooks/useWebsite'; +export * from 'components/hooks/useWebsiteReports'; + +export * from 'components/pages/settings/teams/TeamAddForm'; +export * from 'components/pages/settings/teams/TeamAddWebsiteForm'; +export * from 'components/pages/settings/teams/TeamDeleteForm'; +export * from 'components/pages/settings/teams/TeamEditForm'; +export * from 'components/pages/settings/teams/TeamJoinForm'; +export * from 'components/pages/settings/teams/TeamLeaveForm'; +export * from 'components/pages/settings/teams/TeamMemberRemoveButton'; +export * from 'components/pages/settings/teams/TeamMembers'; +export * from 'components/pages/settings/teams/TeamMembersTable'; +export * from 'components/pages/settings/teams/TeamSettings'; +export * from 'components/pages/settings/teams/TeamsList'; +export * from 'components/pages/settings/teams/TeamsTable'; +export * from 'components/pages/settings/teams/TeamWebsiteRemoveButton'; +export * from 'components/pages/settings/teams/TeamWebsites'; +export * from 'components/pages/settings/teams/TeamWebsitesTable'; +export * from 'components/pages/settings/teams/WebsiteTags'; + +export * from 'components/pages/settings/websites/ShareUrl'; +export * from 'components/pages/settings/websites/TrackingCode'; +export * from 'components/pages/settings/websites/WebsiteAddForm'; +export * from 'components/pages/settings/websites/WebsiteDeleteForm'; +export * from 'components/pages/settings/websites/WebsiteEditForm'; +export * from 'components/pages/settings/websites/WebsiteResetForm'; +export * from 'components/pages/settings/websites/WebsiteSettings'; +export * from 'components/pages/settings/websites/WebsitesList'; +export * from 'components/pages/settings/websites/WebsitesTable'; diff --git a/lang/am-ET.json b/src/lang/am-ET.json similarity index 100% rename from lang/am-ET.json rename to src/lang/am-ET.json diff --git a/lang/ar-SA.json b/src/lang/ar-SA.json similarity index 100% rename from lang/ar-SA.json rename to src/lang/ar-SA.json diff --git a/lang/be-BY.json b/src/lang/be-BY.json similarity index 100% rename from lang/be-BY.json rename to src/lang/be-BY.json diff --git a/lang/bn-BD.json b/src/lang/bn-BD.json similarity index 100% rename from lang/bn-BD.json rename to src/lang/bn-BD.json diff --git a/lang/ca-ES.json b/src/lang/ca-ES.json similarity index 100% rename from lang/ca-ES.json rename to src/lang/ca-ES.json diff --git a/lang/cs-CZ.json b/src/lang/cs-CZ.json similarity index 100% rename from lang/cs-CZ.json rename to src/lang/cs-CZ.json diff --git a/lang/da-DK.json b/src/lang/da-DK.json similarity index 100% rename from lang/da-DK.json rename to src/lang/da-DK.json diff --git a/lang/de-CH.json b/src/lang/de-CH.json similarity index 100% rename from lang/de-CH.json rename to src/lang/de-CH.json diff --git a/lang/de-DE.json b/src/lang/de-DE.json similarity index 100% rename from lang/de-DE.json rename to src/lang/de-DE.json diff --git a/lang/el-GR.json b/src/lang/el-GR.json similarity index 100% rename from lang/el-GR.json rename to src/lang/el-GR.json diff --git a/lang/en-GB.json b/src/lang/en-GB.json similarity index 100% rename from lang/en-GB.json rename to src/lang/en-GB.json diff --git a/lang/en-US.json b/src/lang/en-US.json similarity index 100% rename from lang/en-US.json rename to src/lang/en-US.json diff --git a/lang/es-ES.json b/src/lang/es-ES.json similarity index 100% rename from lang/es-ES.json rename to src/lang/es-ES.json diff --git a/lang/es-MX.json b/src/lang/es-MX.json similarity index 100% rename from lang/es-MX.json rename to src/lang/es-MX.json diff --git a/lang/fa-IR.json b/src/lang/fa-IR.json similarity index 100% rename from lang/fa-IR.json rename to src/lang/fa-IR.json diff --git a/lang/fi-FI.json b/src/lang/fi-FI.json similarity index 100% rename from lang/fi-FI.json rename to src/lang/fi-FI.json diff --git a/lang/fo-FO.json b/src/lang/fo-FO.json similarity index 100% rename from lang/fo-FO.json rename to src/lang/fo-FO.json diff --git a/lang/fr-FR.json b/src/lang/fr-FR.json similarity index 100% rename from lang/fr-FR.json rename to src/lang/fr-FR.json diff --git a/lang/ga-ES.json b/src/lang/ga-ES.json similarity index 100% rename from lang/ga-ES.json rename to src/lang/ga-ES.json diff --git a/lang/he-IL.json b/src/lang/he-IL.json similarity index 100% rename from lang/he-IL.json rename to src/lang/he-IL.json diff --git a/lang/hi-IN.json b/src/lang/hi-IN.json similarity index 100% rename from lang/hi-IN.json rename to src/lang/hi-IN.json diff --git a/lang/hr-HR.json b/src/lang/hr-HR.json similarity index 100% rename from lang/hr-HR.json rename to src/lang/hr-HR.json diff --git a/lang/hu-HU.json b/src/lang/hu-HU.json similarity index 100% rename from lang/hu-HU.json rename to src/lang/hu-HU.json diff --git a/lang/id-ID.json b/src/lang/id-ID.json similarity index 100% rename from lang/id-ID.json rename to src/lang/id-ID.json diff --git a/lang/it-IT.json b/src/lang/it-IT.json similarity index 100% rename from lang/it-IT.json rename to src/lang/it-IT.json diff --git a/lang/ja-JP.json b/src/lang/ja-JP.json similarity index 100% rename from lang/ja-JP.json rename to src/lang/ja-JP.json diff --git a/lang/km-KH.json b/src/lang/km-KH.json similarity index 100% rename from lang/km-KH.json rename to src/lang/km-KH.json diff --git a/lang/ko-KR.json b/src/lang/ko-KR.json similarity index 100% rename from lang/ko-KR.json rename to src/lang/ko-KR.json diff --git a/lang/lt-LT.json b/src/lang/lt-LT.json similarity index 100% rename from lang/lt-LT.json rename to src/lang/lt-LT.json diff --git a/lang/mn-MN.json b/src/lang/mn-MN.json similarity index 100% rename from lang/mn-MN.json rename to src/lang/mn-MN.json diff --git a/lang/ms-MY.json b/src/lang/ms-MY.json similarity index 100% rename from lang/ms-MY.json rename to src/lang/ms-MY.json diff --git a/lang/my-MM.json b/src/lang/my-MM.json similarity index 100% rename from lang/my-MM.json rename to src/lang/my-MM.json diff --git a/lang/nb-NO.json b/src/lang/nb-NO.json similarity index 100% rename from lang/nb-NO.json rename to src/lang/nb-NO.json diff --git a/lang/nl-NL.json b/src/lang/nl-NL.json similarity index 100% rename from lang/nl-NL.json rename to src/lang/nl-NL.json diff --git a/lang/pl-PL.json b/src/lang/pl-PL.json similarity index 100% rename from lang/pl-PL.json rename to src/lang/pl-PL.json diff --git a/lang/pt-BR.json b/src/lang/pt-BR.json similarity index 100% rename from lang/pt-BR.json rename to src/lang/pt-BR.json diff --git a/lang/pt-PT.json b/src/lang/pt-PT.json similarity index 100% rename from lang/pt-PT.json rename to src/lang/pt-PT.json diff --git a/lang/ro-RO.json b/src/lang/ro-RO.json similarity index 100% rename from lang/ro-RO.json rename to src/lang/ro-RO.json diff --git a/lang/ru-RU.json b/src/lang/ru-RU.json similarity index 100% rename from lang/ru-RU.json rename to src/lang/ru-RU.json diff --git a/lang/si-LK.json b/src/lang/si-LK.json similarity index 100% rename from lang/si-LK.json rename to src/lang/si-LK.json diff --git a/lang/sk-SK.json b/src/lang/sk-SK.json similarity index 100% rename from lang/sk-SK.json rename to src/lang/sk-SK.json diff --git a/lang/sl-SI.json b/src/lang/sl-SI.json similarity index 100% rename from lang/sl-SI.json rename to src/lang/sl-SI.json diff --git a/lang/sv-SE.json b/src/lang/sv-SE.json similarity index 100% rename from lang/sv-SE.json rename to src/lang/sv-SE.json diff --git a/lang/ta-IN.json b/src/lang/ta-IN.json similarity index 100% rename from lang/ta-IN.json rename to src/lang/ta-IN.json diff --git a/lang/th-TH.json b/src/lang/th-TH.json similarity index 100% rename from lang/th-TH.json rename to src/lang/th-TH.json diff --git a/lang/tr-TR.json b/src/lang/tr-TR.json similarity index 100% rename from lang/tr-TR.json rename to src/lang/tr-TR.json diff --git a/lang/uk-UA.json b/src/lang/uk-UA.json similarity index 100% rename from lang/uk-UA.json rename to src/lang/uk-UA.json diff --git a/lang/ur-PK.json b/src/lang/ur-PK.json similarity index 100% rename from lang/ur-PK.json rename to src/lang/ur-PK.json diff --git a/lang/vi-VN.json b/src/lang/vi-VN.json similarity index 100% rename from lang/vi-VN.json rename to src/lang/vi-VN.json diff --git a/lang/zh-CN.json b/src/lang/zh-CN.json similarity index 100% rename from lang/zh-CN.json rename to src/lang/zh-CN.json diff --git a/lang/zh-TW.json b/src/lang/zh-TW.json similarity index 100% rename from lang/zh-TW.json rename to src/lang/zh-TW.json diff --git a/lib/auth.ts b/src/lib/auth.ts similarity index 90% rename from lib/auth.ts rename to src/lib/auth.ts index 10f7fbca..4a42d85d 100644 --- a/lib/auth.ts +++ b/src/lib/auth.ts @@ -4,11 +4,12 @@ import debug from 'debug'; import { PERMISSIONS, ROLE_PERMISSIONS, SHARE_TOKEN_HEADER } from 'lib/constants'; import { secret } from 'lib/crypto'; import { createSecureToken, ensureArray, getRandomChars, parseToken } from 'next-basics'; -import { getTeamUser, getTeamWebsite, findTeamWebsiteByUserId } from 'queries'; +import { findTeamWebsiteByUserId, getTeamUser, getTeamWebsite } from 'queries'; import { loadWebsite } from './load'; import { Auth } from './types'; const log = debug('umami:auth'); +const cloudMode = process.env.CLOUD_MODE; export async function setAuthKey(user, expire = 0) { const authKey = `auth:${getRandomChars(32)}`; @@ -57,7 +58,15 @@ export async function canViewWebsite({ user, shareToken }: Auth, websiteId: stri return !!(await findTeamWebsiteByUserId(websiteId, user.id)); } -export async function canCreateWebsite({ user }: Auth) { +export async function canCreateWebsite({ user, grant }: Auth) { + if (cloudMode) { + if (grant?.find(a => a === PERMISSIONS.websiteCreate)) { + return true; + } + + return false; + } + if (user.isAdmin) { return true; } @@ -109,7 +118,15 @@ export async function canDeleteReport(auth: Auth, report: Report) { return canUpdateReport(auth, report); } -export async function canCreateTeam({ user }: Auth) { +export async function canCreateTeam({ user, grant }: Auth) { + if (cloudMode) { + if (grant?.find(a => a === PERMISSIONS.teamCreate)) { + return true; + } + + return false; + } + if (user.isAdmin) { return true; } diff --git a/lib/cache.ts b/src/lib/cache.ts similarity index 72% rename from lib/cache.ts rename to src/lib/cache.ts index bc46c23d..c54eda2e 100644 --- a/lib/cache.ts +++ b/src/lib/cache.ts @@ -2,17 +2,20 @@ import { User, Website } from '@prisma/client'; import redis from '@umami/redis-client'; import { getSession, getUserById, getWebsiteById } from '../queries'; -const { fetchObject, storeObject, deleteObject } = redis; +const { fetchObject, storeObject, deleteObject, expire } = redis; async function fetchWebsite(id): Promise { - return fetchObject(`website:${id}`, () => getWebsiteById(id)); + return fetchObject(`website:${id}`, () => getWebsiteById(id), 86400); } async function storeWebsite(data) { const { id } = data; const key = `website:${id}`; - return storeObject(key, data); + const obj = await storeObject(key, data); + await expire(key, 86400); + + return obj; } async function deleteWebsite(id) { @@ -20,14 +23,17 @@ async function deleteWebsite(id) { } async function fetchUser(id): Promise { - return fetchObject(`user:${id}`, () => getUserById(id, { includePassword: true })); + return fetchObject(`user:${id}`, () => getUserById(id, { includePassword: true }), 86400); } async function storeUser(data) { const { id } = data; const key = `user:${id}`; - return storeObject(key, data); + const obj = await storeObject(key, data); + await expire(key, 86400); + + return obj; } async function deleteUser(id) { @@ -35,14 +41,17 @@ async function deleteUser(id) { } async function fetchSession(id) { - return fetchObject(`session:${id}`, () => getSession(id)); + return fetchObject(`session:${id}`, () => getSession(id), 86400); } async function storeSession(data) { const { id } = data; const key = `session:${id}`; - return storeObject(key, data); + const obj = await storeObject(key, data); + await expire(key, 86400); + + return obj; } async function deleteSession(id) { diff --git a/lib/charts.js b/src/lib/charts.js similarity index 100% rename from lib/charts.js rename to src/lib/charts.js diff --git a/lib/clickhouse.ts b/src/lib/clickhouse.ts similarity index 100% rename from lib/clickhouse.ts rename to src/lib/clickhouse.ts diff --git a/lib/client.ts b/src/lib/client.ts similarity index 100% rename from lib/client.ts rename to src/lib/client.ts diff --git a/lib/constants.ts b/src/lib/constants.ts similarity index 100% rename from lib/constants.ts rename to src/lib/constants.ts diff --git a/lib/crypto.js b/src/lib/crypto.js similarity index 100% rename from lib/crypto.js rename to src/lib/crypto.js diff --git a/lib/data.ts b/src/lib/data.ts similarity index 100% rename from lib/data.ts rename to src/lib/data.ts diff --git a/lib/date.js b/src/lib/date.ts similarity index 79% rename from lib/date.js rename to src/lib/date.ts index 49bff897..14f0e13c 100644 --- a/lib/date.js +++ b/src/lib/date.ts @@ -29,9 +29,19 @@ import { max, min, isDate, + subWeeks, } from 'date-fns'; import { getDateLocale } from 'lib/lang'; +export const TIME_UNIT = { + minute: 'minute', + hour: 'hour', + day: 'day', + week: 'week', + month: 'month', + year: 'year', +}; + const dateFuncs = { minute: [differenceInMinutes, addMinutes, startOfMinute], hour: [differenceInHours, addHours, startOfHour], @@ -81,6 +91,7 @@ export function parseDateRange(value, locale = 'en-US') { if (!match) return null; const { num, unit } = match.groups; + const selectedUnit = { num, unit }; if (+num === 1) { switch (unit) { @@ -90,6 +101,7 @@ export function parseDateRange(value, locale = 'en-US') { endDate: endOfDay(now), unit: 'hour', value, + selectedUnit, }; case 'week': return { @@ -97,6 +109,7 @@ export function parseDateRange(value, locale = 'en-US') { endDate: endOfWeek(now, { locale: dateLocale }), unit: 'day', value, + selectedUnit, }; case 'month': return { @@ -104,6 +117,7 @@ export function parseDateRange(value, locale = 'en-US') { endDate: endOfMonth(now), unit: 'day', value, + selectedUnit, }; case 'year': return { @@ -111,6 +125,7 @@ export function parseDateRange(value, locale = 'en-US') { endDate: endOfYear(now), unit: 'month', value, + selectedUnit, }; } } @@ -123,6 +138,7 @@ export function parseDateRange(value, locale = 'en-US') { endDate: subDays(endOfDay(now), 1), unit: 'hour', value, + selectedUnit, }; case 'week': return { @@ -130,6 +146,7 @@ export function parseDateRange(value, locale = 'en-US') { endDate: subDays(endOfWeek(now, { locale: dateLocale }), 1), unit: 'day', value, + selectedUnit, }; case 'month': return { @@ -137,6 +154,7 @@ export function parseDateRange(value, locale = 'en-US') { endDate: subMonths(endOfMonth(now), 1), unit: 'day', value, + selectedUnit, }; case 'year': return { @@ -144,6 +162,7 @@ export function parseDateRange(value, locale = 'en-US') { endDate: subYears(endOfYear(now), 1), unit: 'month', value, + selectedUnit, }; } } @@ -155,6 +174,7 @@ export function parseDateRange(value, locale = 'en-US') { endDate: endOfDay(now), unit, value, + selectedUnit, }; case 'hour': return { @@ -162,6 +182,53 @@ export function parseDateRange(value, locale = 'en-US') { endDate: endOfHour(now), unit, value, + selectedUnit, + }; + } +} + +export function incrementDateRange(value, increment) { + const { startDate, endDate, selectedUnit } = value; + + const { num, unit } = selectedUnit; + + const sub = num * increment; + + switch (unit) { + case 'hour': + return { + ...value, + startDate: subHours(startDate, sub), + endDate: subHours(endDate, sub), + value: 'range', + }; + case 'day': + return { + ...value, + startDate: subDays(startDate, sub), + endDate: subDays(endDate, sub), + value: 'range', + }; + case 'week': + return { + ...value, + startDate: subWeeks(startDate, sub), + endDate: subWeeks(endDate, sub), + value: 'range', + }; + case 'month': + return { + ...value, + startDate: subMonths(startDate, sub), + endDate: subMonths(endDate, sub), + value: 'range', + }; + case 'year': + return { + ...value, + startDate: subYears(startDate, sub), + endDate: subYears(endDate, sub), + value: 'range', }; } } @@ -237,7 +304,7 @@ export function getDateLength(startDate, endDate, unit) { return diff(endDate, startDate) + 1; } -export const customFormats = { +export const CUSTOM_FORMATS = { 'en-US': { p: 'ha', pp: 'h:mm:ss', @@ -252,7 +319,7 @@ export const customFormats = { export function formatDate(date, str, locale = 'en-US') { return format( typeof date === 'string' ? new Date(date) : date, - customFormats?.[locale]?.[str] || str, + CUSTOM_FORMATS?.[locale]?.[str] || str, { locale: getDateLocale(locale), }, diff --git a/lib/db.js b/src/lib/db.js similarity index 100% rename from lib/db.js rename to src/lib/db.js diff --git a/lib/detect.ts b/src/lib/detect.ts similarity index 100% rename from lib/detect.ts rename to src/lib/detect.ts diff --git a/lib/filters.js b/src/lib/filters.js similarity index 100% rename from lib/filters.js rename to src/lib/filters.js diff --git a/lib/format.js b/src/lib/format.js similarity index 100% rename from lib/format.js rename to src/lib/format.js diff --git a/lib/kafka.ts b/src/lib/kafka.ts similarity index 100% rename from lib/kafka.ts rename to src/lib/kafka.ts diff --git a/lib/lang.js b/src/lib/lang.js similarity index 100% rename from lib/lang.js rename to src/lib/lang.js diff --git a/lib/load.ts b/src/lib/load.ts similarity index 100% rename from lib/load.ts rename to src/lib/load.ts diff --git a/lib/middleware.ts b/src/lib/middleware.ts similarity index 74% rename from lib/middleware.ts rename to src/lib/middleware.ts index 414cab23..edf3e929 100644 --- a/lib/middleware.ts +++ b/src/lib/middleware.ts @@ -1,19 +1,20 @@ +import redis from '@umami/redis-client'; +import cors from 'cors'; +import debug from 'debug'; +import { getAuthToken, parseShareToken } from 'lib/auth'; +import { ROLES } from 'lib/constants'; +import { isUuid, secret } from 'lib/crypto'; +import { findSession } from 'lib/session'; import { - createMiddleware, - unauthorized, badRequest, + createMiddleware, parseSecureToken, tooManyRequest, + unauthorized, } from 'next-basics'; -import debug from 'debug'; -import cors from 'cors'; -import redis from '@umami/redis-client'; -import { findSession } from 'lib/session'; -import { getAuthToken, parseShareToken } from 'lib/auth'; -import { secret, isUuid } from 'lib/crypto'; -import { ROLES } from 'lib/constants'; -import { getUserById } from '../queries'; import { NextApiRequestCollect } from 'pages/api/send'; +import { getUserById } from '../queries'; +import { NextApiRequestQueryBody } from './types'; const log = debug('umami:middleware'); @@ -50,7 +51,7 @@ export const useAuth = createMiddleware(async (req, res, next) => { const shareToken = await parseShareToken(req); let user = null; - const { userId, authKey } = payload || {}; + const { userId, authKey, grant } = payload || {}; if (isUuid(userId)) { user = await getUserById(userId); @@ -59,7 +60,7 @@ export const useAuth = createMiddleware(async (req, res, next) => { } if (process.env.NODE_ENV === 'development') { - log({ token, shareToken, payload, user }); + log({ token, shareToken, payload, user, grant }); } if (!user?.id && !shareToken) { @@ -71,7 +72,25 @@ export const useAuth = createMiddleware(async (req, res, next) => { user.isAdmin = user.role === ROLES.admin; } - (req as any).auth = { user, token, shareToken, authKey }; + (req as any).auth = { + user, + grant, + token, + shareToken, + authKey, + }; + + next(); +}); + +export const useValidate = createMiddleware(async (req: any, res, next) => { + try { + const { yup } = req as NextApiRequestQueryBody; + + yup[req.method] && yup[req.method].validateSync({ ...req.query, ...req.body }); + } catch (e: any) { + return badRequest(res, e.message); + } next(); }); diff --git a/lib/prisma.ts b/src/lib/prisma.ts similarity index 98% rename from lib/prisma.ts rename to src/lib/prisma.ts index 12bafa51..a9832c28 100644 --- a/lib/prisma.ts +++ b/src/lib/prisma.ts @@ -185,7 +185,7 @@ function getPageFilters(filters: SearchFilter): [ orderBy: string; }, ] { - const { pageSize = 10, page = 1, orderBy } = filters; + const { pageSize = 10, page = 1, orderBy } = filters || {}; return [ { diff --git a/lib/query.ts b/src/lib/query.ts similarity index 100% rename from lib/query.ts rename to src/lib/query.ts diff --git a/lib/session.ts b/src/lib/session.ts similarity index 75% rename from lib/session.ts rename to src/lib/session.ts index 5eb7398a..85c173c5 100644 --- a/lib/session.ts +++ b/src/lib/session.ts @@ -1,12 +1,27 @@ -import { secret, uuid, isUuid } from 'lib/crypto'; +import { isUuid, secret, uuid } from 'lib/crypto'; import { getClientInfo, getJsonBody } from 'lib/detect'; import { parseToken } from 'next-basics'; import { CollectRequestBody, NextApiRequestCollect } from 'pages/api/send'; import { createSession } from 'queries'; import cache from './cache'; +import clickhouse from './clickhouse'; import { loadSession, loadWebsite } from './load'; -export async function findSession(req: NextApiRequestCollect) { +export async function findSession(req: NextApiRequestCollect): Promise<{ + id: any; + websiteId: string; + hostname: string; + browser: string; + os: any; + device: string; + screen: string; + language: string; + country: any; + subdivision1: any; + subdivision2: any; + city: any; + ownerId: string; +}> { const { payload } = getJsonBody(req); if (!payload) { @@ -53,6 +68,25 @@ export async function findSession(req: NextApiRequestCollect) { const sessionId = uuid(websiteId, hostname, ip, userAgent); + // Clickhouse does not require session lookup + if (clickhouse.enabled) { + return { + id: sessionId, + websiteId, + hostname, + browser, + os: os as any, + device, + screen, + language, + country, + subdivision1, + subdivision2, + city, + ownerId: website.userId, + }; + } + // Find session let session = await loadSession(sessionId); diff --git a/lib/sql.ts b/src/lib/sql.ts similarity index 100% rename from lib/sql.ts rename to src/lib/sql.ts diff --git a/lib/types.ts b/src/lib/types.ts similarity index 87% rename from lib/types.ts rename to src/lib/types.ts index 3f3ac533..3685753e 100644 --- a/lib/types.ts +++ b/src/lib/types.ts @@ -4,20 +4,29 @@ import { DATA_TYPE, EVENT_TYPE, KAFKA_TOPIC, + PERMISSIONS, REPORT_FILTER_TYPES, + REPORT_TYPES, ROLES, TEAM_FILTER_TYPES, USER_FILTER_TYPES, WEBSITE_FILTER_TYPES, } from './constants'; +import * as yup from 'yup'; +import { TIME_UNIT } from './date'; type ObjectValues = T[keyof T]; +export type TimeUnit = ObjectValues; +export type Permission = ObjectValues; + export type CollectionType = ObjectValues; export type Role = ObjectValues; export type EventType = ObjectValues; export type DynamicDataType = ObjectValues; export type KafkaTopic = ObjectValues; +export type ReportType = ObjectValues; + export type ReportSearchFilterType = ObjectValues; export type UserSearchFilterType = ObjectValues; export type WebsiteSearchFilterType = ObjectValues; @@ -47,8 +56,8 @@ export interface ReportSearchFilter extends SearchFilter export interface SearchFilter { filter?: string; filterType?: T; - pageSize?: number; - page?: number; + pageSize: number; + page: number; orderBy?: string; } @@ -71,16 +80,25 @@ export interface Auth { role: string; isAdmin: boolean; }; + grant?: Permission[]; shareToken?: { websiteId: string; }; } +export interface YupRequest { + GET?: yup.ObjectSchema; + POST?: yup.ObjectSchema; + PUT?: yup.ObjectSchema; + DELETE?: yup.ObjectSchema; +} + export interface NextApiRequestQueryBody extends NextApiRequest { auth?: Auth; query: TQuery & { [key: string]: string | string[] }; body: TBody; headers: any; + yup: YupRequest; } export interface NextApiRequestAuth extends NextApiRequest { @@ -168,8 +186,9 @@ export interface RealtimeUpdate { export interface DateRange { startDate: Date; endDate: Date; - unit: string; value: string; + unit?: TimeUnit; + selectedUnit?: TimeUnit; } export interface QueryFilters { diff --git a/src/lib/yup.ts b/src/lib/yup.ts new file mode 100644 index 00000000..a9d21028 --- /dev/null +++ b/src/lib/yup.ts @@ -0,0 +1,19 @@ +import * as yup from 'yup'; + +export function getDateRangeValidation() { + return { + startAt: yup.number().integer().required(), + endAt: yup.number().integer().moreThan(yup.ref('startAt')).required(), + }; +} + +// ex: /funnel|insights|retention/i +export function getFilterValidation(matchRegex) { + return { + filter: yup.string(), + filterType: yup.string().matches(matchRegex), + pageSize: yup.number().integer().positive().max(200), + page: yup.number().integer().positive(), + orderBy: yup.string(), + }; +} diff --git a/pages/404.js b/src/pages/404.js similarity index 90% rename from pages/404.js rename to src/pages/404.js index 4a5f4bd9..8fa13a9c 100644 --- a/pages/404.js +++ b/src/pages/404.js @@ -1,6 +1,6 @@ import { Row, Column, Flexbox } from 'react-basics'; import AppLayout from 'components/layout/AppLayout'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export default function Custom404() { const { formatMessage, labels } = useMessages(); diff --git a/pages/_app.js b/src/pages/_app.js similarity index 96% rename from pages/_app.js rename to src/pages/_app.js index 8d549773..e88b2d86 100644 --- a/pages/_app.js +++ b/src/pages/_app.js @@ -5,8 +5,8 @@ import Head from 'next/head'; import Script from 'next/script'; import { useRouter } from 'next/router'; import ErrorBoundary from 'components/common/ErrorBoundary'; -import useLocale from 'hooks/useLocale'; -import useConfig from 'hooks/useConfig'; +import useLocale from 'components/hooks/useLocale'; +import useConfig from 'components/hooks/useConfig'; import '@fontsource/inter/400.css'; import '@fontsource/inter/700.css'; import 'react-basics/dist/styles.css'; diff --git a/pages/api/auth/login.ts b/src/pages/api/auth/login.ts similarity index 85% rename from pages/api/auth/login.ts rename to src/pages/api/auth/login.ts index b9a2be00..47521084 100644 --- a/pages/api/auth/login.ts +++ b/src/pages/api/auth/login.ts @@ -1,19 +1,20 @@ +import redis from '@umami/redis-client'; import debug from 'debug'; +import { setAuthKey } from 'lib/auth'; +import { secret } from 'lib/crypto'; +import { useValidate } from 'lib/middleware'; +import { NextApiRequestQueryBody, User } from 'lib/types'; import { NextApiResponse } from 'next'; import { - ok, - unauthorized, - badRequest, checkPassword, createSecureToken, - methodNotAllowed, forbidden, + methodNotAllowed, + ok, + unauthorized, } from 'next-basics'; -import redis from '@umami/redis-client'; import { getUserByUsername } from 'queries'; -import { secret } from 'lib/crypto'; -import { NextApiRequestQueryBody, User } from 'lib/types'; -import { setAuthKey } from 'lib/auth'; +import * as yup from 'yup'; const log = debug('umami:auth'); @@ -27,6 +28,13 @@ export interface LoginResponse { user: User; } +const schema = { + POST: yup.object().shape({ + username: yup.string().required(), + password: yup.string().required(), + }), +}; + export default async ( req: NextApiRequestQueryBody, res: NextApiResponse, @@ -35,13 +43,12 @@ export default async ( return forbidden(res); } + req.yup = schema; + await useValidate(req, res); + if (req.method === 'POST') { const { username, password } = req.body; - if (!username || !password) { - return badRequest(res); - } - const user = await getUserByUsername(username, { includePassword: true }); if (user && checkPassword(password, user.password)) { diff --git a/pages/api/auth/logout.ts b/src/pages/api/auth/logout.ts similarity index 100% rename from pages/api/auth/logout.ts rename to src/pages/api/auth/logout.ts diff --git a/pages/api/auth/sso.ts b/src/pages/api/auth/sso.ts similarity index 100% rename from pages/api/auth/sso.ts rename to src/pages/api/auth/sso.ts diff --git a/pages/api/auth/verify.ts b/src/pages/api/auth/verify.ts similarity index 100% rename from pages/api/auth/verify.ts rename to src/pages/api/auth/verify.ts diff --git a/pages/api/config.ts b/src/pages/api/config.ts similarity index 100% rename from pages/api/config.ts rename to src/pages/api/config.ts diff --git a/pages/api/event-data/events.ts b/src/pages/api/event-data/events.ts similarity index 56% rename from pages/api/event-data/events.ts rename to src/pages/api/event-data/events.ts index 9f8f964b..1d1d3787 100644 --- a/pages/api/event-data/events.ts +++ b/src/pages/api/event-data/events.ts @@ -1,26 +1,37 @@ import { canViewWebsite } from 'lib/auth'; -import { useCors, useAuth } from 'lib/middleware'; +import { useAuth, useCors, useValidate } from 'lib/middleware'; import { NextApiRequestQueryBody } from 'lib/types'; import { NextApiResponse } from 'next'; -import { ok, methodNotAllowed, unauthorized } from 'next-basics'; +import { methodNotAllowed, ok, unauthorized } from 'next-basics'; import { getEventDataEvents } from 'queries'; +import * as yup from 'yup'; -export interface EventDataEventsRequestQuery { +export interface EventDataFieldsRequestQuery { websiteId: string; - dateRange: { - startDate: string; - endDate: string; - }; + startAt: string; + endAt: string; event?: string; } +const schema = { + GET: yup.object().shape({ + websiteId: yup.string().uuid().required(), + startAt: yup.number().integer().required(), + endAt: yup.number().integer().moreThan(yup.ref('startAt')).required(), + event: yup.string(), + }), +}; + export default async ( - req: NextApiRequestQueryBody, + req: NextApiRequestQueryBody, res: NextApiResponse, ) => { await useCors(req, res); await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + if (req.method === 'GET') { const { websiteId, startAt, endAt, event } = req.query; diff --git a/pages/api/event-data/fields.ts b/src/pages/api/event-data/fields.ts similarity index 63% rename from pages/api/event-data/fields.ts rename to src/pages/api/event-data/fields.ts index b6a73133..1cd24fe6 100644 --- a/pages/api/event-data/fields.ts +++ b/src/pages/api/event-data/fields.ts @@ -1,19 +1,27 @@ import { canViewWebsite } from 'lib/auth'; -import { useCors, useAuth } from 'lib/middleware'; +import { useAuth, useCors, useValidate } from 'lib/middleware'; import { NextApiRequestQueryBody } from 'lib/types'; import { NextApiResponse } from 'next'; -import { ok, methodNotAllowed, unauthorized } from 'next-basics'; +import { methodNotAllowed, ok, unauthorized } from 'next-basics'; import { getEventDataFields } from 'queries'; +import * as yup from 'yup'; export interface EventDataFieldsRequestQuery { websiteId: string; - dateRange: { - startDate: string; - endDate: string; - }; + startAt: string; + endAt: string; field?: string; } +const schema = { + GET: yup.object().shape({ + websiteId: yup.string().uuid().required(), + startAt: yup.number().integer().required(), + endAt: yup.number().integer().moreThan(yup.ref('startAt')).required(), + field: yup.string(), + }), +}; + export default async ( req: NextApiRequestQueryBody, res: NextApiResponse, @@ -21,6 +29,9 @@ export default async ( await useCors(req, res); await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + if (req.method === 'GET') { const { websiteId, startAt, endAt, field } = req.query; diff --git a/pages/api/event-data/stats.ts b/src/pages/api/event-data/stats.ts similarity index 60% rename from pages/api/event-data/stats.ts rename to src/pages/api/event-data/stats.ts index 4ba843be..7f694bc6 100644 --- a/pages/api/event-data/stats.ts +++ b/src/pages/api/event-data/stats.ts @@ -1,18 +1,25 @@ import { canViewWebsite } from 'lib/auth'; -import { useCors, useAuth } from 'lib/middleware'; +import { useAuth, useCors, useValidate } from 'lib/middleware'; import { NextApiRequestQueryBody } from 'lib/types'; import { NextApiResponse } from 'next'; -import { ok, methodNotAllowed, unauthorized } from 'next-basics'; -import { getEventDataStats } from 'queries'; +import { methodNotAllowed, ok, unauthorized } from 'next-basics'; +import { getEventDataStats } from 'queries/index'; +import * as yup from 'yup'; export interface EventDataStatsRequestQuery { websiteId: string; - dateRange: { - startDate: string; - endDate: string; - }; + startAt: string; + endAt: string; } +const schema = { + GET: yup.object().shape({ + websiteId: yup.string().uuid().required(), + startAt: yup.number().integer().required(), + endAt: yup.number().integer().moreThan(yup.ref('startAt')).required(), + }), +}; + export default async ( req: NextApiRequestQueryBody, res: NextApiResponse, @@ -20,6 +27,9 @@ export default async ( await useCors(req, res); await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + if (req.method === 'GET') { const { websiteId, startAt, endAt } = req.query; diff --git a/pages/api/heartbeat.ts b/src/pages/api/heartbeat.ts similarity index 100% rename from pages/api/heartbeat.ts rename to src/pages/api/heartbeat.ts diff --git a/pages/api/me/index.ts b/src/pages/api/me/index.ts similarity index 100% rename from pages/api/me/index.ts rename to src/pages/api/me/index.ts diff --git a/pages/api/me/password.ts b/src/pages/api/me/password.ts similarity index 77% rename from pages/api/me/password.ts rename to src/pages/api/me/password.ts index f9f60fc5..6f49a182 100644 --- a/pages/api/me/password.ts +++ b/src/pages/api/me/password.ts @@ -1,15 +1,16 @@ +import { useAuth, useValidate } from 'lib/middleware'; import { NextApiRequestQueryBody, User } from 'lib/types'; -import { useAuth } from 'lib/middleware'; import { NextApiResponse } from 'next'; import { badRequest, checkPassword, + forbidden, hashPassword, methodNotAllowed, - forbidden, ok, } from 'next-basics'; import { getUserById, updateUser } from 'queries'; +import * as yup from 'yup'; export interface UserPasswordRequestQuery { id: string; @@ -20,6 +21,14 @@ export interface UserPasswordRequestBody { newPassword: string; } +const schema = { + POST: yup.object().shape({ + id: yup.string().uuid().required(), + currentPassword: yup.string().required(), + newPassword: yup.string().min(8).required(), + }), +}; + export default async ( req: NextApiRequestQueryBody, res: NextApiResponse, @@ -30,6 +39,9 @@ export default async ( await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + const { currentPassword, newPassword } = req.body; const { id } = req.auth.user; diff --git a/pages/api/me/teams.ts b/src/pages/api/me/teams.ts similarity index 60% rename from pages/api/me/teams.ts rename to src/pages/api/me/teams.ts index d323043b..d394ef07 100644 --- a/pages/api/me/teams.ts +++ b/src/pages/api/me/teams.ts @@ -1,10 +1,20 @@ -import { useCors } from 'lib/middleware'; +import { useCors, useValidate } from 'lib/middleware'; import { NextApiRequestQueryBody, SearchFilter, TeamSearchFilterType } from 'lib/types'; +import { getFilterValidation } from 'lib/yup'; import { NextApiResponse } from 'next'; import { methodNotAllowed } from 'next-basics'; import userTeams from 'pages/api/users/[id]/teams'; +import * as yup from 'yup'; -export interface MyTeamsRequestQuery extends SearchFilter {} +export interface MyTeamsRequestQuery extends SearchFilter { + id: string; +} + +const schema = { + GET: yup.object().shape({ + ...getFilterValidation(/All|Name|Owner/i), + }), +}; export default async ( req: NextApiRequestQueryBody, @@ -12,7 +22,12 @@ export default async ( ) => { await useCors(req, res); + req.yup = schema; + await useValidate(req, res); + if (req.method === 'GET') { + req.query.id = req.auth.user.id; + return userTeams(req, res); } diff --git a/pages/api/me/websites.ts b/src/pages/api/me/websites.ts similarity index 64% rename from pages/api/me/websites.ts rename to src/pages/api/me/websites.ts index 238d1b6e..d4a803a0 100644 --- a/pages/api/me/websites.ts +++ b/src/pages/api/me/websites.ts @@ -1,11 +1,20 @@ -import { useAuth, useCors } from 'lib/middleware'; +import { useAuth, useCors, useValidate } from 'lib/middleware'; import { NextApiRequestQueryBody, SearchFilter, WebsiteSearchFilterType } from 'lib/types'; +import { getFilterValidation } from 'lib/yup'; import { NextApiResponse } from 'next'; import { methodNotAllowed } from 'next-basics'; - import userWebsites from 'pages/api/users/[id]/websites'; +import * as yup from 'yup'; -export interface MyWebsitesRequestQuery extends SearchFilter {} +export interface MyWebsitesRequestQuery extends SearchFilter { + id: string; +} + +const schema = { + GET: yup.object().shape({ + ...getFilterValidation(/All|Name|Domain/i), + }), +}; export default async ( req: NextApiRequestQueryBody, @@ -14,6 +23,9 @@ export default async ( await useCors(req, res); await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + if (req.method === 'GET') { req.query.id = req.auth.user.id; diff --git a/pages/api/realtime/[id].ts b/src/pages/api/realtime/[id].ts similarity index 77% rename from pages/api/realtime/[id].ts rename to src/pages/api/realtime/[id].ts index e78599c6..5b1e1e05 100644 --- a/pages/api/realtime/[id].ts +++ b/src/pages/api/realtime/[id].ts @@ -1,22 +1,32 @@ import { subMinutes } from 'date-fns'; import { canViewWebsite } from 'lib/auth'; -import { useAuth } from 'lib/middleware'; +import { useAuth, useValidate } from 'lib/middleware'; import { NextApiRequestQueryBody, RealtimeInit } from 'lib/types'; import { NextApiResponse } from 'next'; import { methodNotAllowed, ok, unauthorized } from 'next-basics'; import { getRealtimeData } from 'queries'; - +import * as yup from 'yup'; export interface RealtimeRequestQuery { id: string; startAt: number; } +const schema = { + GET: yup.object().shape({ + id: yup.string().uuid().required(), + startAt: yup.number().integer().required(), + }), +}; + export default async ( req: NextApiRequestQueryBody, res: NextApiResponse, ) => { await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + if (req.method === 'GET') { const { id: websiteId, startAt } = req.query; diff --git a/pages/api/reports/[id].ts b/src/pages/api/reports/[id].ts similarity index 61% rename from pages/api/reports/[id].ts rename to src/pages/api/reports/[id].ts index 85bc302c..eb4199bc 100644 --- a/pages/api/reports/[id].ts +++ b/src/pages/api/reports/[id].ts @@ -1,9 +1,10 @@ -import { canUpdateReport, canViewReport, canDeleteReport } from 'lib/auth'; -import { useAuth, useCors } from 'lib/middleware'; -import { NextApiRequestQueryBody } from 'lib/types'; +import { canDeleteReport, canUpdateReport, canViewReport } from 'lib/auth'; +import { useAuth, useCors, useValidate } from 'lib/middleware'; +import { NextApiRequestQueryBody, ReportType, YupRequest } from 'lib/types'; import { NextApiResponse } from 'next'; import { methodNotAllowed, ok, unauthorized } from 'next-basics'; -import { getReportById, updateReport, deleteReport } from 'queries'; +import { deleteReport, getReportById, updateReport } from 'queries'; +import * as yup from 'yup'; export interface ReportRequestQuery { id: string; @@ -11,12 +12,34 @@ export interface ReportRequestQuery { export interface ReportRequestBody { websiteId: string; - type: string; + type: ReportType; name: string; description: string; parameters: string; } +const schema: YupRequest = { + GET: yup.object().shape({ + id: yup.string().uuid().required(), + }), + POST: yup.object().shape({ + id: yup.string().uuid().required(), + websiteId: yup.string().uuid().required(), + type: yup + .string() + .matches(/funnel|insights|retention/i) + .required(), + name: yup.string().max(200).required(), + description: yup.string().max(500), + parameters: yup + .object() + .test('len', 'Must not exceed 6000 characters.', val => JSON.stringify(val).length < 6000), + }), + DELETE: yup.object().shape({ + id: yup.string().uuid().required(), + }), +}; + export default async ( req: NextApiRequestQueryBody, res: NextApiResponse, @@ -24,6 +47,9 @@ export default async ( await useCors(req, res); await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + const { id: reportId } = req.query; const { user: { id: userId }, diff --git a/pages/api/reports/funnel.ts b/src/pages/api/reports/funnel.ts similarity index 65% rename from pages/api/reports/funnel.ts rename to src/pages/api/reports/funnel.ts index 33882e03..a51817bf 100644 --- a/pages/api/reports/funnel.ts +++ b/src/pages/api/reports/funnel.ts @@ -1,9 +1,10 @@ import { canViewWebsite } from 'lib/auth'; -import { useCors, useAuth } from 'lib/middleware'; +import { useAuth, useCors, useValidate } from 'lib/middleware'; import { NextApiRequestQueryBody } from 'lib/types'; import { NextApiResponse } from 'next'; -import { ok, methodNotAllowed, unauthorized } from 'next-basics'; +import { methodNotAllowed, ok, unauthorized } from 'next-basics'; import { getFunnel } from 'queries'; +import * as yup from 'yup'; export interface FunnelRequestBody { websiteId: string; @@ -22,6 +23,21 @@ export interface FunnelResponse { endAt: number; } +const schema = { + POST: yup.object().shape({ + websiteId: yup.string().uuid().required(), + urls: yup.array().min(2).of(yup.string()).required(), + window: yup.number().positive().required(), + dateRange: yup + .object() + .shape({ + startDate: yup.date().required(), + endDate: yup.date().required(), + }) + .required(), + }), +}; + export default async ( req: NextApiRequestQueryBody, res: NextApiResponse, @@ -29,6 +45,9 @@ export default async ( await useCors(req, res); await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + if (req.method === 'POST') { const { websiteId, diff --git a/pages/api/reports/index.ts b/src/pages/api/reports/index.ts similarity index 58% rename from pages/api/reports/index.ts rename to src/pages/api/reports/index.ts index 762f297c..e62a1cc5 100644 --- a/pages/api/reports/index.ts +++ b/src/pages/api/reports/index.ts @@ -1,10 +1,11 @@ -import { canViewWebsite } from 'lib/auth'; import { uuid } from 'lib/crypto'; -import { useAuth, useCors } from 'lib/middleware'; +import { useAuth, useCors, useValidate } from 'lib/middleware'; import { NextApiRequestQueryBody, ReportSearchFilterType, SearchFilter } from 'lib/types'; +import { getFilterValidation } from 'lib/yup'; import { NextApiResponse } from 'next'; -import { methodNotAllowed, ok, unauthorized } from 'next-basics'; -import { createReport, getReportsByUserId, getReportsByWebsiteId } from 'queries'; +import { methodNotAllowed, ok } from 'next-basics'; +import { createReport, getReportsByUserId } from 'queries'; +import * as yup from 'yup'; export interface ReportsRequestQuery extends SearchFilter {} @@ -14,11 +15,28 @@ export interface ReportRequestBody { type: string; description: string; parameters: { - window: string; - urls: string[]; + [key: string]: any; }; } +const schema = { + GET: yup.object().shape({ + ...getFilterValidation(/All|Name|Description|Type|Username|Website Name|Website Domain/i), + }), + POST: yup.object().shape({ + websiteId: yup.string().uuid().required(), + name: yup.string().max(200).required(), + type: yup + .string() + .matches(/funnel|insights|retention/i) + .required(), + description: yup.string().max(500), + parameters: yup + .object() + .test('len', 'Must not exceed 6000 characters.', val => JSON.stringify(val).length < 6000), + }), +}; + export default async ( req: NextApiRequestQueryBody, res: NextApiResponse, @@ -26,6 +44,9 @@ export default async ( await useCors(req, res); await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + const { user: { id: userId }, } = req.auth; diff --git a/src/pages/api/reports/insights.ts b/src/pages/api/reports/insights.ts new file mode 100644 index 00000000..4d17c922 --- /dev/null +++ b/src/pages/api/reports/insights.ts @@ -0,0 +1,98 @@ +import { canViewWebsite } from 'lib/auth'; +import { useAuth, useCors, useValidate } from 'lib/middleware'; +import { NextApiRequestQueryBody } from 'lib/types'; +import { NextApiResponse } from 'next'; +import { methodNotAllowed, ok, unauthorized } from 'next-basics'; +import { getInsights } from 'queries'; +import * as yup from 'yup'; + +export interface InsightsRequestBody { + websiteId: string; + dateRange: { + startDate: string; + endDate: string; + }; + fields: { name: string; type: string; label: string }[]; + filters: { name: string; type: string; filter: string; value: string }[]; + groups: { name: string; type: string }[]; +} + +const schema = { + POST: yup.object().shape({ + websiteId: yup.string().uuid().required(), + dateRange: yup + .object() + .shape({ + startDate: yup.date().required(), + endDate: yup.date().required(), + }) + .required(), + fields: yup + .array() + .of( + yup.object().shape({ + name: yup.string().required(), + type: yup.string().required(), + label: yup.string().required(), + }), + ) + .min(1) + .required(), + filters: yup.array().of( + yup.object().shape({ + name: yup.string().required(), + type: yup.string().required(), + filter: yup.string().required(), + value: yup.string().required(), + }), + ), + groups: yup.array().of( + yup.object().shape({ + name: yup.string().required(), + type: yup.string().required(), + }), + ), + }), +}; + +function convertFilters(filters) { + return filters.reduce((obj, { name, ...value }) => { + obj[name] = value; + + return obj; + }, {}); +} + +export default async ( + req: NextApiRequestQueryBody, + res: NextApiResponse, +) => { + await useCors(req, res); + await useAuth(req, res); + + req.yup = schema; + await useValidate(req, res); + + if (req.method === 'POST') { + const { + websiteId, + dateRange: { startDate, endDate }, + fields, + filters, + } = req.body; + + if (!(await canViewWebsite(req.auth, websiteId))) { + return unauthorized(res); + } + + const data = await getInsights(websiteId, fields, { + ...convertFilters(filters), + startDate: new Date(startDate), + endDate: new Date(endDate), + }); + + return ok(res, data); + } + + return methodNotAllowed(res); +}; diff --git a/pages/api/reports/retention.ts b/src/pages/api/reports/retention.ts similarity index 59% rename from pages/api/reports/retention.ts rename to src/pages/api/reports/retention.ts index 40b3266b..4006ab12 100644 --- a/pages/api/reports/retention.ts +++ b/src/pages/api/reports/retention.ts @@ -1,33 +1,43 @@ import { canViewWebsite } from 'lib/auth'; -import { useCors, useAuth } from 'lib/middleware'; +import { useAuth, useCors, useValidate } from 'lib/middleware'; import { NextApiRequestQueryBody } from 'lib/types'; import { NextApiResponse } from 'next'; -import { ok, methodNotAllowed, unauthorized } from 'next-basics'; +import { methodNotAllowed, ok, unauthorized } from 'next-basics'; import { getRetention } from 'queries'; +import * as yup from 'yup'; export interface RetentionRequestBody { websiteId: string; - dateRange: { window; startDate: string; endDate: string }; - timezone: string; + dateRange: { startDate: string; endDate: string }; } -export interface RetentionResponse { - startAt: number; - endAt: number; -} +const schema = { + POST: yup.object().shape({ + websiteId: yup.string().uuid().required(), + dateRange: yup + .object() + .shape({ + startDate: yup.date().required(), + endDate: yup.date().required(), + }) + .required(), + }), +}; export default async ( req: NextApiRequestQueryBody, - res: NextApiResponse, + res: NextApiResponse, ) => { await useCors(req, res); await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + if (req.method === 'POST') { const { websiteId, dateRange: { startDate, endDate }, - timezone, } = req.body; if (!(await canViewWebsite(req.auth, websiteId))) { @@ -37,7 +47,6 @@ export default async ( const data = await getRetention(websiteId, { startDate: new Date(startDate), endDate: new Date(endDate), - timezone, }); return ok(res, data); diff --git a/pages/api/scripts/telemetry.js b/src/pages/api/scripts/telemetry.js similarity index 100% rename from pages/api/scripts/telemetry.js rename to src/pages/api/scripts/telemetry.js diff --git a/pages/api/send.ts b/src/pages/api/send.ts similarity index 78% rename from pages/api/send.ts rename to src/pages/api/send.ts index f90ded77..a379f261 100644 --- a/pages/api/send.ts +++ b/src/pages/api/send.ts @@ -1,14 +1,15 @@ -import isbot from 'isbot'; -import ipaddr from 'ipaddr.js'; -import { createToken, ok, send, badRequest, forbidden } from 'next-basics'; -import { saveEvent, saveSessionData } from 'queries'; -import { useCors, useSession } from 'lib/middleware'; -import { getJsonBody, getIpAddress } from 'lib/detect'; -import { secret } from 'lib/crypto'; -import { NextApiRequest, NextApiResponse } from 'next'; import { Resolver } from 'dns/promises'; -import { CollectionType } from 'lib/types'; -import { COLLECTION_TYPE } from 'lib/constants'; +import ipaddr from 'ipaddr.js'; +import isbot from 'isbot'; +import { COLLECTION_TYPE, HOSTNAME_REGEX } from 'lib/constants'; +import { secret } from 'lib/crypto'; +import { getIpAddress, getJsonBody } from 'lib/detect'; +import { useCors, useSession, useValidate } from 'lib/middleware'; +import { CollectionType, YupRequest } from 'lib/types'; +import { NextApiRequest, NextApiResponse } from 'next'; +import { badRequest, createToken, forbidden, ok, send } from 'next-basics'; +import { saveEvent, saveSessionData } from 'queries'; +import * as yup from 'yup'; export interface CollectRequestBody { payload: { @@ -43,8 +44,32 @@ export interface NextApiRequestCollect extends NextApiRequest { city: string; }; headers: { [key: string]: any }; + yup: YupRequest; } +const schema = { + POST: yup.object().shape({ + payload: yup + .object() + .shape({ + data: yup.object(), + hostname: yup.string().matches(HOSTNAME_REGEX).max(100), + language: yup.string().max(35), + referrer: yup.string().max(500), + screen: yup.string().max(11), + title: yup.string().max(500), + url: yup.string().max(500), + website: yup.string().uuid().required(), + name: yup.string().max(50), + }) + .required(), + type: yup + .string() + .matches(/event|identify/i) + .required(), + }), +}; + export default async (req: NextApiRequestCollect, res: NextApiResponse) => { await useCors(req, res); @@ -54,11 +79,8 @@ export default async (req: NextApiRequestCollect, res: NextApiResponse) => { const { type, payload } = getJsonBody(req); - const error = validateBody({ type, payload }); - - if (error) { - return badRequest(res, error); - } + req.yup = schema; + await useValidate(req, res); if (await hasBlockedIp(req)) { return forbidden(res); @@ -118,22 +140,6 @@ export default async (req: NextApiRequestCollect, res: NextApiResponse) => { return send(res, token); }; -function validateBody({ type, payload }: CollectRequestBody) { - if (!type || !payload) { - return 'Invalid payload.'; - } - - if (type !== COLLECTION_TYPE.event && type !== COLLECTION_TYPE.identify) { - return 'Wrong payload type.'; - } - - const { data } = payload; - - if (data && !(typeof data === 'object' && !Array.isArray(data))) { - return 'Invalid event data.'; - } -} - async function hasBlockedIp(req: NextApiRequestCollect) { const ignoreIps = process.env.IGNORE_IP; const ignoreHostnames = process.env.IGNORE_HOSTNAME; diff --git a/pages/api/share/[id].ts b/src/pages/api/share/[id].ts similarity index 79% rename from pages/api/share/[id].ts rename to src/pages/api/share/[id].ts index 0592d216..ad642283 100644 --- a/pages/api/share/[id].ts +++ b/src/pages/api/share/[id].ts @@ -1,8 +1,10 @@ -import { NextApiRequestQueryBody } from 'lib/types'; import { secret } from 'lib/crypto'; +import { useValidate } from 'lib/middleware'; +import { NextApiRequestQueryBody } from 'lib/types'; import { NextApiResponse } from 'next'; import { createToken, methodNotAllowed, notFound, ok } from 'next-basics'; import { getWebsiteByShareId } from 'queries'; +import * as yup from 'yup'; export interface ShareRequestQuery { id: string; @@ -13,10 +15,19 @@ export interface ShareResponse { token: string; } +const schema = { + GET: yup.object().shape({ + id: yup.string().uuid().required(), + }), +}; + export default async ( req: NextApiRequestQueryBody, res: NextApiResponse, ) => { + req.yup = schema; + await useValidate(req, res); + const { id: shareId } = req.query; if (req.method === 'GET') { diff --git a/pages/api/teams/[id]/index.ts b/src/pages/api/teams/[id]/index.ts similarity index 75% rename from pages/api/teams/[id]/index.ts rename to src/pages/api/teams/[id]/index.ts index 7fb664a0..31c47b2f 100644 --- a/pages/api/teams/[id]/index.ts +++ b/src/pages/api/teams/[id]/index.ts @@ -1,10 +1,11 @@ import { Team } from '@prisma/client'; -import { NextApiRequestQueryBody } from 'lib/types'; import { canDeleteTeam, canUpdateTeam, canViewTeam } from 'lib/auth'; -import { useAuth } from 'lib/middleware'; +import { useAuth, useValidate } from 'lib/middleware'; +import { NextApiRequestQueryBody } from 'lib/types'; import { NextApiResponse } from 'next'; import { methodNotAllowed, ok, unauthorized } from 'next-basics'; import { deleteTeam, getTeamById, updateTeam } from 'queries'; +import * as yup from 'yup'; export interface TeamRequestQuery { id: string; @@ -15,12 +16,29 @@ export interface TeamRequestBody { accessCode: string; } +const schema = { + GET: yup.object().shape({ + id: yup.string().uuid().required(), + }), + POST: yup.object().shape({ + id: yup.string().uuid().required(), + name: yup.string().max(50).required(), + accessCode: yup.string().max(50).required(), + }), + DELETE: yup.object().shape({ + id: yup.string().uuid().required(), + }), +}; + export default async ( req: NextApiRequestQueryBody, res: NextApiResponse, ) => { await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + const { id: teamId } = req.query; if (req.method === 'GET') { diff --git a/pages/api/teams/[id]/users/[userId].ts b/src/pages/api/teams/[id]/users/[userId].ts similarity index 73% rename from pages/api/teams/[id]/users/[userId].ts rename to src/pages/api/teams/[id]/users/[userId].ts index 1e4ca623..adb635d5 100644 --- a/pages/api/teams/[id]/users/[userId].ts +++ b/src/pages/api/teams/[id]/users/[userId].ts @@ -1,18 +1,28 @@ import { canDeleteTeamUser } from 'lib/auth'; -import { useAuth } from 'lib/middleware'; +import { useAuth, useValidate } from 'lib/middleware'; import { NextApiRequestQueryBody } from 'lib/types'; import { NextApiResponse } from 'next'; import { methodNotAllowed, ok, unauthorized } from 'next-basics'; import { deleteTeamUser } from 'queries'; - +import * as yup from 'yup'; export interface TeamUserRequestQuery { id: string; userId: string; } +const schema = { + DELETE: yup.object().shape({ + id: yup.string().uuid().required(), + userId: yup.string().uuid().required(), + }), +}; + export default async (req: NextApiRequestQueryBody, res: NextApiResponse) => { await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + if (req.method === 'DELETE') { const { id: teamId, userId } = req.query; diff --git a/pages/api/teams/[id]/users/index.ts b/src/pages/api/teams/[id]/users/index.ts similarity index 57% rename from pages/api/teams/[id]/users/index.ts rename to src/pages/api/teams/[id]/users/index.ts index 6f8b077e..52b25da6 100644 --- a/pages/api/teams/[id]/users/index.ts +++ b/src/pages/api/teams/[id]/users/index.ts @@ -1,9 +1,9 @@ -import { canUpdateTeam, canViewTeam } from 'lib/auth'; +import { canViewTeam } from 'lib/auth'; import { useAuth } from 'lib/middleware'; import { NextApiRequestQueryBody, SearchFilter, TeamSearchFilterType } from 'lib/types'; import { NextApiResponse } from 'next'; -import { badRequest, methodNotAllowed, ok, unauthorized } from 'next-basics'; -import { createTeamUser, getUserByUsername, getUsersByTeamId } from 'queries'; +import { methodNotAllowed, ok, unauthorized } from 'next-basics'; +import { getUsersByTeamId } from 'queries'; export interface TeamUserRequestQuery extends SearchFilter { id: string; @@ -38,24 +38,5 @@ export default async ( return ok(res, users); } - if (req.method === 'POST') { - if (!(await canUpdateTeam(req.auth, teamId))) { - return unauthorized(res, 'You must be the owner of this team.'); - } - - const { email, roleId: roleId } = req.body; - - // Check for User - const user = await getUserByUsername(email); - - if (!user) { - return badRequest(res, 'The User does not exists.'); - } - - const updated = await createTeamUser(user.id, teamId, roleId); - - return ok(res, updated); - } - return methodNotAllowed(res); }; diff --git a/pages/api/teams/[id]/websites/[websiteId].ts b/src/pages/api/teams/[id]/websites/[websiteId].ts similarity index 73% rename from pages/api/teams/[id]/websites/[websiteId].ts rename to src/pages/api/teams/[id]/websites/[websiteId].ts index 795295d3..ada1efdc 100644 --- a/pages/api/teams/[id]/websites/[websiteId].ts +++ b/src/pages/api/teams/[id]/websites/[websiteId].ts @@ -1,21 +1,32 @@ import { canDeleteTeamWebsite } from 'lib/auth'; -import { useAuth } from 'lib/middleware'; +import { useAuth, useValidate } from 'lib/middleware'; import { NextApiRequestQueryBody } from 'lib/types'; import { NextApiResponse } from 'next'; import { methodNotAllowed, ok, unauthorized } from 'next-basics'; import { deleteTeamWebsite } from 'queries/admin/teamWebsite'; +import * as yup from 'yup'; export interface TeamWebsitesRequestQuery { id: string; websiteId: string; } +const schema = { + DELETE: yup.object().shape({ + id: yup.string().uuid().required(), + websiteId: yup.string().uuid().required(), + }), +}; + export default async ( req: NextApiRequestQueryBody, res: NextApiResponse, ) => { await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + const { id: teamId, websiteId } = req.query; if (req.method === 'DELETE') { diff --git a/pages/api/teams/[id]/websites/index.ts b/src/pages/api/teams/[id]/websites/index.ts similarity index 71% rename from pages/api/teams/[id]/websites/index.ts rename to src/pages/api/teams/[id]/websites/index.ts index dcd08939..4de32709 100644 --- a/pages/api/teams/[id]/websites/index.ts +++ b/src/pages/api/teams/[id]/websites/index.ts @@ -1,9 +1,10 @@ import { canViewTeam } from 'lib/auth'; -import { useAuth } from 'lib/middleware'; +import { useAuth, useValidate } from 'lib/middleware'; import { NextApiRequestQueryBody, SearchFilter, WebsiteSearchFilterType } from 'lib/types'; +import { getFilterValidation } from 'lib/yup'; import { NextApiResponse } from 'next'; import { methodNotAllowed, ok, unauthorized } from 'next-basics'; -import { getWebsites, getWebsitesByTeamId } from 'queries'; +import { getWebsitesByTeamId } from 'queries'; import { createTeamWebsites } from 'queries/admin/teamWebsite'; export interface TeamWebsiteRequestQuery extends SearchFilter { @@ -14,12 +15,28 @@ export interface TeamWebsiteRequestBody { websiteIds?: string[]; } +import * as yup from 'yup'; + +const schema = { + GET: yup.object().shape({ + id: yup.string().uuid().required(), + ...getFilterValidation(/All|Name|Domain/i), + }), + POST: yup.object().shape({ + id: yup.string().uuid().required(), + websiteIds: yup.array().of(yup.string()).min(1).required(), + }), +}; + export default async ( req: NextApiRequestQueryBody, res: NextApiResponse, ) => { await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + const { id: teamId } = req.query; if (req.method === 'GET') { diff --git a/pages/api/teams/index.ts b/src/pages/api/teams/index.ts similarity index 72% rename from pages/api/teams/index.ts rename to src/pages/api/teams/index.ts index 997ed885..dd742b9e 100644 --- a/pages/api/teams/index.ts +++ b/src/pages/api/teams/index.ts @@ -1,23 +1,39 @@ import { Team } from '@prisma/client'; import { canCreateTeam } from 'lib/auth'; import { uuid } from 'lib/crypto'; -import { useAuth } from 'lib/middleware'; +import { useAuth, useValidate } from 'lib/middleware'; import { NextApiRequestQueryBody, SearchFilter, TeamSearchFilterType } from 'lib/types'; +import { getFilterValidation } from 'lib/yup'; import { NextApiResponse } from 'next'; import { getRandomChars, methodNotAllowed, ok, unauthorized } from 'next-basics'; import { createTeam, getTeamsByUserId } from 'queries'; +import * as yup from 'yup'; export interface TeamsRequestQuery extends SearchFilter {} -export interface TeamsRequestBody extends SearchFilter { +export interface TeamsRequestBody { name: string; } +export interface MyTeamsRequestQuery extends SearchFilter {} + +const schema = { + GET: yup.object().shape({ + ...getFilterValidation(/All|Name|Owner/i), + }), + POST: yup.object().shape({ + name: yup.string().max(50).required(), + }), +}; + export default async ( req: NextApiRequestQueryBody, res: NextApiResponse, ) => { await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + const { user: { id: userId }, } = req.auth; diff --git a/pages/api/teams/join.ts b/src/pages/api/teams/join.ts similarity index 76% rename from pages/api/teams/join.ts rename to src/pages/api/teams/join.ts index ce7367a0..06feda8a 100644 --- a/pages/api/teams/join.ts +++ b/src/pages/api/teams/join.ts @@ -1,21 +1,30 @@ import { Team } from '@prisma/client'; -import { NextApiRequestQueryBody } from 'lib/types'; -import { useAuth } from 'lib/middleware'; -import { NextApiResponse } from 'next'; -import { methodNotAllowed, ok, notFound } from 'next-basics'; -import { createTeamUser, getTeamByAccessCode, getTeamUser } from 'queries'; import { ROLES } from 'lib/constants'; - +import { useAuth, useValidate } from 'lib/middleware'; +import { NextApiRequestQueryBody } from 'lib/types'; +import { NextApiResponse } from 'next'; +import { methodNotAllowed, notFound, ok } from 'next-basics'; +import { createTeamUser, getTeamByAccessCode, getTeamUser } from 'queries'; +import * as yup from 'yup'; export interface TeamsJoinRequestBody { accessCode: string; } +const schema = { + POST: yup.object().shape({ + accessCode: yup.string().max(50).required(), + }), +}; + export default async ( req: NextApiRequestQueryBody, res: NextApiResponse, ) => { await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + if (req.method === 'POST') { const { accessCode } = req.body; diff --git a/pages/api/users/[id]/index.ts b/src/pages/api/users/[id]/index.ts similarity index 82% rename from pages/api/users/[id]/index.ts rename to src/pages/api/users/[id]/index.ts index e09b1b5f..3ac560ed 100644 --- a/pages/api/users/[id]/index.ts +++ b/src/pages/api/users/[id]/index.ts @@ -1,9 +1,10 @@ -import { NextApiRequestQueryBody, Role, User } from 'lib/types'; import { canDeleteUser, canUpdateUser, canViewUser } from 'lib/auth'; -import { useAuth } from 'lib/middleware'; +import { useAuth, useValidate } from 'lib/middleware'; +import { NextApiRequestQueryBody, Role, User } from 'lib/types'; import { NextApiResponse } from 'next'; import { badRequest, hashPassword, methodNotAllowed, ok, unauthorized } from 'next-basics'; import { deleteUser, getUserById, getUserByUsername, updateUser } from 'queries'; +import * as yup from 'yup'; export interface UserRequestQuery { id: string; @@ -15,12 +16,27 @@ export interface UserRequestBody { role: Role; } +const schema = { + GET: yup.object().shape({ + id: yup.string().uuid().required(), + }), + POST: yup.object().shape({ + id: yup.string().uuid().required(), + username: yup.string().max(255), + password: yup.string(), + role: yup.string().matches(/admin|user|view-only/i), + }), +}; + export default async ( req: NextApiRequestQueryBody, res: NextApiResponse, ) => { await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + const { user: { id: userId, isAdmin }, } = req.auth; diff --git a/pages/api/users/[id]/teams.ts b/src/pages/api/users/[id]/teams.ts similarity index 75% rename from pages/api/users/[id]/teams.ts rename to src/pages/api/users/[id]/teams.ts index 831a992d..eb34410c 100644 --- a/pages/api/users/[id]/teams.ts +++ b/src/pages/api/users/[id]/teams.ts @@ -1,9 +1,10 @@ -import { useAuth, useCors } from 'lib/middleware'; +import { useAuth, useCors, useValidate } from 'lib/middleware'; import { NextApiRequestQueryBody, SearchFilter, TeamSearchFilterType } from 'lib/types'; +import { getFilterValidation } from 'lib/yup'; import { NextApiResponse } from 'next'; import { methodNotAllowed, ok, unauthorized } from 'next-basics'; import { getTeamsByUserId } from 'queries'; - +import * as yup from 'yup'; export interface UserTeamsRequestQuery extends SearchFilter { id: string; } @@ -14,6 +15,13 @@ export interface UserTeamsRequestBody { shareId: string; } +const schema = { + GET: yup.object().shape({ + id: yup.string().uuid().required(), + ...getFilterValidation('/All|Name|Owner/i'), + }), +}; + export default async ( req: NextApiRequestQueryBody, res: NextApiResponse, @@ -21,6 +29,9 @@ export default async ( await useCors(req, res); await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + const { user } = req.auth; const { id: userId } = req.query; diff --git a/pages/api/users/[id]/usage.ts b/src/pages/api/users/[id]/usage.ts similarity index 84% rename from pages/api/users/[id]/usage.ts rename to src/pages/api/users/[id]/usage.ts index 0118df92..b0fc2055 100644 --- a/pages/api/users/[id]/usage.ts +++ b/src/pages/api/users/[id]/usage.ts @@ -1,8 +1,9 @@ -import { useAuth, useCors } from 'lib/middleware'; +import { useAuth, useCors, useValidate } from 'lib/middleware'; import { NextApiRequestQueryBody } from 'lib/types'; import { NextApiResponse } from 'next'; import { methodNotAllowed, ok, unauthorized } from 'next-basics'; import { getEventDataUsage, getEventUsage, getUserWebsites } from 'queries'; +import * as yup from 'yup'; export interface UserUsageRequestQuery { id: string; @@ -21,6 +22,14 @@ export interface UserUsageRequestResponse { }[]; } +const schema = { + GET: yup.object().shape({ + id: yup.string().uuid().required(), + startAt: yup.number().integer().required(), + endAt: yup.number().integer().moreThan(yup.ref('startAt')).required(), + }), +}; + export default async ( req: NextApiRequestQueryBody, res: NextApiResponse, @@ -28,6 +37,9 @@ export default async ( await useCors(req, res); await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + const { user } = req.auth; if (req.method === 'GET') { diff --git a/pages/api/users/[id]/websites.ts b/src/pages/api/users/[id]/websites.ts similarity index 64% rename from pages/api/users/[id]/websites.ts rename to src/pages/api/users/[id]/websites.ts index 0e9231f7..65e9a0e8 100644 --- a/pages/api/users/[id]/websites.ts +++ b/src/pages/api/users/[id]/websites.ts @@ -1,25 +1,36 @@ -import { useAuth, useCors } from 'lib/middleware'; +import { useAuth, useCors, useValidate } from 'lib/middleware'; import { NextApiRequestQueryBody, SearchFilter, WebsiteSearchFilterType } from 'lib/types'; +import { getFilterValidation } from 'lib/yup'; import { NextApiResponse } from 'next'; import { methodNotAllowed, ok, unauthorized } from 'next-basics'; import { getWebsitesByUserId } from 'queries'; +import * as yup from 'yup'; export interface UserWebsitesRequestQuery extends SearchFilter { id: string; -} -export interface UserWebsitesRequestBody { - name: string; - domain: string; - shareId: string; + includeTeams?: boolean; + onlyTeams?: boolean; } +const schema = { + GET: yup.object().shape({ + id: yup.string().uuid().required(), + includeTeams: yup.boolean(), + onlyTeams: yup.boolean(), + ...getFilterValidation(/All|Name|Domain/i), + }), +}; + export default async ( - req: NextApiRequestQueryBody, + req: NextApiRequestQueryBody, res: NextApiResponse, ) => { await useCors(req, res); await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + const { user } = req.auth; const { id: userId, page, filter, pageSize, includeTeams, onlyTeams } = req.query; diff --git a/pages/api/users/index.ts b/src/pages/api/users/index.ts similarity index 71% rename from pages/api/users/index.ts rename to src/pages/api/users/index.ts index 5e913c02..0b523c70 100644 --- a/pages/api/users/index.ts +++ b/src/pages/api/users/index.ts @@ -1,8 +1,9 @@ import { canCreateUser, canViewUsers } from 'lib/auth'; import { ROLES } from 'lib/constants'; import { uuid } from 'lib/crypto'; -import { useAuth } from 'lib/middleware'; +import { useAuth, useValidate } from 'lib/middleware'; import { NextApiRequestQueryBody, Role, SearchFilter, User, UserSearchFilterType } from 'lib/types'; +import { getFilterValidation } from 'lib/yup'; import { NextApiResponse } from 'next'; import { badRequest, hashPassword, methodNotAllowed, ok, unauthorized } from 'next-basics'; import { createUser, getUserByUsername, getUsers } from 'queries'; @@ -15,12 +16,31 @@ export interface UsersRequestBody { role?: Role; } +import * as yup from 'yup'; +const schema = { + GET: yup.object().shape({ + ...getFilterValidation(/All|Username/i), + }), + POST: yup.object().shape({ + username: yup.string().max(255).required(), + password: yup.string().required(), + id: yup.string().uuid(), + role: yup + .string() + .matches(/admin|user|view-only/i) + .required(), + }), +}; + export default async ( req: NextApiRequestQueryBody, res: NextApiResponse, ) => { await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + if (req.method === 'GET') { if (!(await canViewUsers(req.auth))) { return unauthorized(res); @@ -28,7 +48,7 @@ export default async ( const { page, filter, pageSize } = req.query; - const users = await getUsers({ page, filter, pageSize: +pageSize || null }); + const users = await getUsers({ page, filter, pageSize: pageSize ? +pageSize : null }); return ok(res, users); } diff --git a/pages/api/websites/[id]/active.ts b/src/pages/api/websites/[id]/active.ts similarity index 76% rename from pages/api/websites/[id]/active.ts rename to src/pages/api/websites/[id]/active.ts index 99c8d999..abc23dd7 100644 --- a/pages/api/websites/[id]/active.ts +++ b/src/pages/api/websites/[id]/active.ts @@ -1,14 +1,21 @@ import { WebsiteActive, NextApiRequestQueryBody } from 'lib/types'; import { canViewWebsite } from 'lib/auth'; -import { useAuth, useCors } from 'lib/middleware'; +import { useAuth, useCors, useValidate } from 'lib/middleware'; import { NextApiResponse } from 'next'; import { methodNotAllowed, ok, unauthorized } from 'next-basics'; import { getActiveVisitors } from 'queries'; +import * as yup from 'yup'; export interface WebsiteActiveRequestQuery { id: string; } +const schema = { + GET: yup.object().shape({ + id: yup.string().uuid().required(), + }), +}; + export default async ( req: NextApiRequestQueryBody, res: NextApiResponse, @@ -16,6 +23,9 @@ export default async ( await useCors(req, res); await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + const { id: websiteId } = req.query; if (req.method === 'GET') { diff --git a/pages/api/websites/[id]/daterange.ts b/src/pages/api/websites/[id]/daterange.ts similarity index 77% rename from pages/api/websites/[id]/daterange.ts rename to src/pages/api/websites/[id]/daterange.ts index dc043560..bfa5338e 100644 --- a/pages/api/websites/[id]/daterange.ts +++ b/src/pages/api/websites/[id]/daterange.ts @@ -1,14 +1,21 @@ import { WebsiteActive, NextApiRequestQueryBody } from 'lib/types'; import { canViewWebsite } from 'lib/auth'; -import { useAuth, useCors } from 'lib/middleware'; +import { useAuth, useCors, useValidate } from 'lib/middleware'; import { NextApiResponse } from 'next'; import { methodNotAllowed, ok, unauthorized } from 'next-basics'; import { getWebsiteDateRange } from 'queries'; +import * as yup from 'yup'; export interface WebsiteDateRangeRequestQuery { id: string; } +const schema = { + GET: yup.object().shape({ + id: yup.string().uuid().required(), + }), +}; + export default async ( req: NextApiRequestQueryBody, res: NextApiResponse, @@ -16,6 +23,9 @@ export default async ( await useCors(req, res); await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + const { id: websiteId } = req.query; if (req.method === 'GET') { diff --git a/pages/api/websites/[id]/events.ts b/src/pages/api/websites/[id]/events.ts similarity index 70% rename from pages/api/websites/[id]/events.ts rename to src/pages/api/websites/[id]/events.ts index 7d4f999f..427cb40e 100644 --- a/pages/api/websites/[id]/events.ts +++ b/src/pages/api/websites/[id]/events.ts @@ -1,6 +1,6 @@ import { WebsiteMetric, NextApiRequestQueryBody } from 'lib/types'; import { canViewWebsite } from 'lib/auth'; -import { useAuth, useCors } from 'lib/middleware'; +import { useAuth, useCors, useValidate } from 'lib/middleware'; import moment from 'moment-timezone'; import { NextApiResponse } from 'next'; import { badRequest, methodNotAllowed, ok, unauthorized } from 'next-basics'; @@ -16,9 +16,21 @@ export interface WebsiteEventsRequestQuery { unit: string; timezone: string; url: string; - eventName: string; } +import * as yup from 'yup'; + +const schema = { + GET: yup.object().shape({ + id: yup.string().uuid().required(), + startAt: yup.number().integer().required(), + endAt: yup.number().integer().moreThan(yup.ref('startAt')).required(), + unit: yup.string().required(), + timezone: yup.string().required(), + url: yup.string(), + }), +}; + export default async ( req: NextApiRequestQueryBody, res: NextApiResponse, @@ -26,7 +38,10 @@ export default async ( await useCors(req, res); await useAuth(req, res); - const { id: websiteId, timezone, url, eventName } = req.query; + req.yup = schema; + await useValidate(req, res); + + const { id: websiteId, timezone, url } = req.query; const { startDate, endDate, unit } = await parseDateRangeQuery(req); if (req.method === 'GET') { @@ -44,7 +59,6 @@ export default async ( timezone, unit, url, - eventName, }); return ok(res, events); diff --git a/pages/api/websites/[id]/index.ts b/src/pages/api/websites/[id]/index.ts similarity index 88% rename from pages/api/websites/[id]/index.ts rename to src/pages/api/websites/[id]/index.ts index 3d053d0e..0e5aacce 100644 --- a/pages/api/websites/[id]/index.ts +++ b/src/pages/api/websites/[id]/index.ts @@ -2,7 +2,7 @@ import { NextApiResponse } from 'next'; import { methodNotAllowed, ok, serverError, unauthorized } from 'next-basics'; import { Website, NextApiRequestQueryBody } from 'lib/types'; import { canViewWebsite, canUpdateWebsite, canDeleteWebsite } from 'lib/auth'; -import { useAuth, useCors } from 'lib/middleware'; +import { useAuth, useCors, useValidate } from 'lib/middleware'; import { deleteWebsite, getWebsiteById, updateWebsite } from 'queries'; import { SHARE_ID_REGEX } from 'lib/constants'; @@ -16,6 +16,14 @@ export interface WebsiteRequestBody { shareId: string; } +import * as yup from 'yup'; + +const schema = { + GET: yup.object().shape({ + id: yup.string().uuid().required(), + }), +}; + export default async ( req: NextApiRequestQueryBody, res: NextApiResponse, @@ -23,6 +31,9 @@ export default async ( await useCors(req, res); await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + const { id: websiteId } = req.query; if (req.method === 'GET') { diff --git a/pages/api/websites/[id]/metrics.ts b/src/pages/api/websites/[id]/metrics.ts similarity index 90% rename from pages/api/websites/[id]/metrics.ts rename to src/pages/api/websites/[id]/metrics.ts index 7c84583c..67c15eca 100644 --- a/pages/api/websites/[id]/metrics.ts +++ b/src/pages/api/websites/[id]/metrics.ts @@ -2,10 +2,11 @@ import { NextApiResponse } from 'next'; import { badRequest, methodNotAllowed, ok, unauthorized } from 'next-basics'; import { WebsiteMetric, NextApiRequestQueryBody } from 'lib/types'; import { canViewWebsite } from 'lib/auth'; -import { useAuth, useCors } from 'lib/middleware'; +import { useAuth, useCors, useValidate } from 'lib/middleware'; import { SESSION_COLUMNS, EVENT_COLUMNS, FILTER_COLUMNS } from 'lib/constants'; import { getPageviewMetrics, getSessionMetrics } from 'queries'; import { parseDateRangeQuery } from 'lib/query'; +import * as yup from 'yup'; export interface WebsiteMetricsRequestQuery { id: string; @@ -26,6 +27,12 @@ export interface WebsiteMetricsRequestQuery { language: string; } +const schema = { + GET: yup.object().shape({ + id: yup.string().uuid().required(), + }), +}; + export default async ( req: NextApiRequestQueryBody, res: NextApiResponse, @@ -33,6 +40,9 @@ export default async ( await useCors(req, res); await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + const { id: websiteId, type, diff --git a/pages/api/websites/[id]/pageviews.ts b/src/pages/api/websites/[id]/pageviews.ts similarity index 87% rename from pages/api/websites/[id]/pageviews.ts rename to src/pages/api/websites/[id]/pageviews.ts index c5532e76..9985ca89 100644 --- a/pages/api/websites/[id]/pageviews.ts +++ b/src/pages/api/websites/[id]/pageviews.ts @@ -3,7 +3,7 @@ import { NextApiResponse } from 'next'; import { badRequest, methodNotAllowed, ok, unauthorized } from 'next-basics'; import { NextApiRequestQueryBody, WebsitePageviews } from 'lib/types'; import { canViewWebsite } from 'lib/auth'; -import { useAuth, useCors } from 'lib/middleware'; +import { useAuth, useCors, useValidate } from 'lib/middleware'; import { getPageviewStats, getSessionStats } from 'queries'; import { parseDateRangeQuery } from 'lib/query'; @@ -24,6 +24,13 @@ export interface WebsitePageviewRequestQuery { city?: string; } +import * as yup from 'yup'; +const schema = { + GET: yup.object().shape({ + id: yup.string().uuid().required(), + }), +}; + export default async ( req: NextApiRequestQueryBody, res: NextApiResponse, @@ -31,6 +38,9 @@ export default async ( await useCors(req, res); await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + const { id: websiteId, timezone, diff --git a/pages/api/websites/[id]/reports.ts b/src/pages/api/websites/[id]/reports.ts similarity index 80% rename from pages/api/websites/[id]/reports.ts rename to src/pages/api/websites/[id]/reports.ts index 60c6f714..738f6b37 100644 --- a/pages/api/websites/[id]/reports.ts +++ b/src/pages/api/websites/[id]/reports.ts @@ -1,5 +1,5 @@ import { canViewWebsite } from 'lib/auth'; -import { useAuth, useCors } from 'lib/middleware'; +import { useAuth, useCors, useValidate } from 'lib/middleware'; import { NextApiRequestQueryBody, ReportSearchFilterType, SearchFilter } from 'lib/types'; import { NextApiResponse } from 'next'; import { methodNotAllowed, ok, unauthorized } from 'next-basics'; @@ -9,6 +9,13 @@ export interface ReportsRequestQuery extends SearchFilter, res: NextApiResponse, @@ -16,6 +23,9 @@ export default async ( await useCors(req, res); await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + const { id: websiteId } = req.query; if (req.method === 'GET') { diff --git a/pages/api/websites/[id]/reset.ts b/src/pages/api/websites/[id]/reset.ts similarity index 75% rename from pages/api/websites/[id]/reset.ts rename to src/pages/api/websites/[id]/reset.ts index 23b5305d..cfd5e767 100644 --- a/pages/api/websites/[id]/reset.ts +++ b/src/pages/api/websites/[id]/reset.ts @@ -1,6 +1,6 @@ import { NextApiRequestQueryBody } from 'lib/types'; import { canUpdateWebsite } from 'lib/auth'; -import { useAuth, useCors } from 'lib/middleware'; +import { useAuth, useCors, useValidate } from 'lib/middleware'; import { NextApiResponse } from 'next'; import { methodNotAllowed, ok, unauthorized } from 'next-basics'; import { resetWebsite } from 'queries'; @@ -9,6 +9,13 @@ export interface WebsiteResetRequestQuery { id: string; } +import * as yup from 'yup'; +const schema = { + GET: yup.object().shape({ + id: yup.string().uuid().required(), + }), +}; + export default async ( req: NextApiRequestQueryBody, res: NextApiResponse, @@ -16,6 +23,9 @@ export default async ( await useCors(req, res); await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + const { id: websiteId } = req.query; if (req.method === 'POST') { diff --git a/pages/api/websites/[id]/stats.ts b/src/pages/api/websites/[id]/stats.ts similarity index 89% rename from pages/api/websites/[id]/stats.ts rename to src/pages/api/websites/[id]/stats.ts index a77c7eaf..caf54910 100644 --- a/pages/api/websites/[id]/stats.ts +++ b/src/pages/api/websites/[id]/stats.ts @@ -2,7 +2,7 @@ import { subMinutes, differenceInMinutes } from 'date-fns'; import { NextApiResponse } from 'next'; import { methodNotAllowed, ok, unauthorized } from 'next-basics'; import { canViewWebsite } from 'lib/auth'; -import { useAuth, useCors } from 'lib/middleware'; +import { useAuth, useCors, useValidate } from 'lib/middleware'; import { NextApiRequestQueryBody, WebsiteStats } from 'lib/types'; import { parseDateRangeQuery } from 'lib/query'; import { getWebsiteStats } from 'queries'; @@ -24,6 +24,13 @@ export interface WebsiteStatsRequestQuery { city: string; } +import * as yup from 'yup'; +const schema = { + GET: yup.object().shape({ + id: yup.string().uuid().required(), + }), +}; + export default async ( req: NextApiRequestQueryBody, res: NextApiResponse, @@ -31,6 +38,9 @@ export default async ( await useCors(req, res); await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + const { id: websiteId, url, diff --git a/pages/api/websites/[id]/values.ts b/src/pages/api/websites/[id]/values.ts similarity index 82% rename from pages/api/websites/[id]/values.ts rename to src/pages/api/websites/[id]/values.ts index ad8625bd..d90a1682 100644 --- a/pages/api/websites/[id]/values.ts +++ b/src/pages/api/websites/[id]/values.ts @@ -1,6 +1,6 @@ import { NextApiRequestQueryBody } from 'lib/types'; import { canViewWebsite } from 'lib/auth'; -import { useAuth, useCors } from 'lib/middleware'; +import { useAuth, useCors, useValidate } from 'lib/middleware'; import { NextApiResponse } from 'next'; import { badRequest, methodNotAllowed, ok, unauthorized } from 'next-basics'; import { EVENT_COLUMNS, FILTER_COLUMNS, SESSION_COLUMNS } from 'lib/constants'; @@ -10,6 +10,13 @@ export interface WebsiteResetRequestQuery { id: string; } +import * as yup from 'yup'; +const schema = { + GET: yup.object().shape({ + id: yup.string().uuid().required(), + }), +}; + export default async ( req: NextApiRequestQueryBody, res: NextApiResponse, @@ -17,6 +24,9 @@ export default async ( await useCors(req, res); await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); + const { id: websiteId, type } = req.query; if (req.method === 'GET') { diff --git a/pages/api/websites/index.ts b/src/pages/api/websites/index.ts similarity index 72% rename from pages/api/websites/index.ts rename to src/pages/api/websites/index.ts index f94fa037..d724f12f 100644 --- a/pages/api/websites/index.ts +++ b/src/pages/api/websites/index.ts @@ -1,11 +1,13 @@ import { canCreateWebsite } from 'lib/auth'; import { uuid } from 'lib/crypto'; -import { useAuth, useCors } from 'lib/middleware'; +import { useAuth, useCors, useValidate } from 'lib/middleware'; import { NextApiRequestQueryBody, SearchFilter, WebsiteSearchFilterType } from 'lib/types'; import { NextApiResponse } from 'next'; import { methodNotAllowed, ok, unauthorized } from 'next-basics'; import { createWebsite } from 'queries'; import userWebsites from 'pages/api/users/[id]/websites'; +import * as yup from 'yup'; +import { getFilterValidation } from 'lib/yup'; export interface WebsitesRequestQuery extends SearchFilter {} @@ -15,12 +17,25 @@ export interface WebsitesRequestBody { shareId: string; } +const schema = { + GET: yup.object().shape({ + ...getFilterValidation(/All|Name|Domain/i), + }), + POST: yup.object().shape({ + name: yup.string().max(100).required(), + domain: yup.string().max(500).required(), + shareId: yup.string().max(50), + }), +}; + export default async ( req: NextApiRequestQueryBody, res: NextApiResponse, ) => { await useCors(req, res); await useAuth(req, res); + req.yup = schema; + await useValidate(req, res); const { user: { id: userId }, @@ -30,7 +45,7 @@ export default async ( req.query.id = userId; req.query.pageSize = 100; - return userWebsites(req, res); + return userWebsites(req as any, res); } if (req.method === 'POST') { diff --git a/pages/console/[[...id]].js b/src/pages/console/[[...id]].js similarity index 100% rename from pages/console/[[...id]].js rename to src/pages/console/[[...id]].js diff --git a/pages/dashboard/index.js b/src/pages/dashboard/index.js similarity index 85% rename from pages/dashboard/index.js rename to src/pages/dashboard/index.js index 061697f4..c1a3c09e 100644 --- a/pages/dashboard/index.js +++ b/src/pages/dashboard/index.js @@ -1,6 +1,6 @@ import AppLayout from 'components/layout/AppLayout'; import Dashboard from 'components/pages/dashboard/Dashboard'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export default function DashboardPage() { const { formatMessage, labels } = useMessages(); diff --git a/pages/index.js b/src/pages/index.js similarity index 100% rename from pages/index.js rename to src/pages/index.js diff --git a/pages/login.js b/src/pages/login.js similarity index 100% rename from pages/login.js rename to src/pages/login.js diff --git a/pages/logout.js b/src/pages/logout.js similarity index 93% rename from pages/logout.js rename to src/pages/logout.js index 675f1932..ef89080c 100644 --- a/pages/logout.js +++ b/src/pages/logout.js @@ -1,6 +1,6 @@ import { useEffect } from 'react'; import { useRouter } from 'next/router'; -import useApi from 'hooks/useApi'; +import useApi from 'components/hooks/useApi'; import { setUser } from 'store/app'; import { removeClientAuthToken } from 'lib/client'; diff --git a/pages/reports/[id].js b/src/pages/reports/[id].js similarity index 92% rename from pages/reports/[id].js rename to src/pages/reports/[id].js index 2520e87d..101881a1 100644 --- a/pages/reports/[id].js +++ b/src/pages/reports/[id].js @@ -1,7 +1,7 @@ import { useRouter } from 'next/router'; import AppLayout from 'components/layout/AppLayout'; import ReportDetails from 'components/pages/reports/ReportDetails'; -import { useApi, useMessages } from 'hooks'; +import { useApi, useMessages } from 'components/hooks'; export default function () { const { formatMessage, labels } = useMessages(); diff --git a/pages/reports/create.js b/src/pages/reports/create.js similarity index 87% rename from pages/reports/create.js rename to src/pages/reports/create.js index 763e2c63..08f97f28 100644 --- a/pages/reports/create.js +++ b/src/pages/reports/create.js @@ -1,6 +1,6 @@ import AppLayout from 'components/layout/AppLayout'; import ReportTemplates from 'components/pages/reports/ReportTemplates'; -import { useMessages } from 'hooks'; +import { useMessages } from 'components/hooks'; export default function () { const { formatMessage, labels } = useMessages(); diff --git a/pages/reports/funnel.js b/src/pages/reports/funnel.js similarity index 86% rename from pages/reports/funnel.js rename to src/pages/reports/funnel.js index 4acdef37..78174f7b 100644 --- a/pages/reports/funnel.js +++ b/src/pages/reports/funnel.js @@ -1,6 +1,6 @@ import AppLayout from 'components/layout/AppLayout'; import FunnelReport from 'components/pages/reports/funnel/FunnelReport'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export default function () { const { formatMessage, labels } = useMessages(); diff --git a/pages/reports/index.js b/src/pages/reports/index.js similarity index 86% rename from pages/reports/index.js rename to src/pages/reports/index.js index ff3b4e86..a1a13a68 100644 --- a/pages/reports/index.js +++ b/src/pages/reports/index.js @@ -1,6 +1,6 @@ import AppLayout from 'components/layout/AppLayout'; import ReportsPage from 'components/pages/reports/ReportsPage'; -import { useMessages } from 'hooks'; +import { useMessages } from 'components/hooks'; export default function () { const { formatMessage, labels } = useMessages(); diff --git a/pages/reports/insights.js b/src/pages/reports/insights.js similarity index 88% rename from pages/reports/insights.js rename to src/pages/reports/insights.js index 45236e10..c5220721 100644 --- a/pages/reports/insights.js +++ b/src/pages/reports/insights.js @@ -1,6 +1,6 @@ import AppLayout from 'components/layout/AppLayout'; import InsightsReport from 'components/pages/reports/insights/InsightsReport'; -import { useMessages } from 'hooks'; +import { useMessages } from 'components/hooks'; export default function () { const { formatMessage, labels } = useMessages(); diff --git a/pages/reports/retention.js b/src/pages/reports/retention.js similarity index 86% rename from pages/reports/retention.js rename to src/pages/reports/retention.js index b7f0bd0f..7f5d4cf2 100644 --- a/pages/reports/retention.js +++ b/src/pages/reports/retention.js @@ -1,6 +1,6 @@ import AppLayout from 'components/layout/AppLayout'; import RetentionReport from 'components/pages/reports/retention/RetentionReport'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export default function () { const { formatMessage, labels } = useMessages(); diff --git a/pages/settings/profile/index.js b/src/pages/settings/profile/index.js similarity index 89% rename from pages/settings/profile/index.js rename to src/pages/settings/profile/index.js index 8827f1da..d340c193 100644 --- a/pages/settings/profile/index.js +++ b/src/pages/settings/profile/index.js @@ -1,7 +1,7 @@ import AppLayout from 'components/layout/AppLayout'; import SettingsLayout from 'components/layout/SettingsLayout'; import ProfileSettings from 'components/pages/settings/profile/ProfileSettings'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export default function () { const { formatMessage, labels } = useMessages(); diff --git a/pages/settings/teams/[id].js b/src/pages/settings/teams/[id].js similarity index 93% rename from pages/settings/teams/[id].js rename to src/pages/settings/teams/[id].js index a68ef80c..775a6a08 100644 --- a/pages/settings/teams/[id].js +++ b/src/pages/settings/teams/[id].js @@ -2,7 +2,7 @@ import AppLayout from 'components/layout/AppLayout'; import SettingsLayout from 'components/layout/SettingsLayout'; import TeamSettings from 'components/pages/settings/teams/TeamSettings'; import { useRouter } from 'next/router'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export default function ({ disabled }) { const router = useRouter(); diff --git a/pages/settings/teams/index.js b/src/pages/settings/teams/index.js similarity index 91% rename from pages/settings/teams/index.js rename to src/pages/settings/teams/index.js index 51739c31..7e56a7d7 100644 --- a/pages/settings/teams/index.js +++ b/src/pages/settings/teams/index.js @@ -1,7 +1,7 @@ import AppLayout from 'components/layout/AppLayout'; import SettingsLayout from 'components/layout/SettingsLayout'; import TeamsList from 'components/pages/settings/teams/TeamsList'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export default function ({ disabled }) { const { formatMessage, labels } = useMessages(); diff --git a/pages/settings/users/[id].js b/src/pages/settings/users/[id].js similarity index 93% rename from pages/settings/users/[id].js rename to src/pages/settings/users/[id].js index d1e53419..fdd708fd 100644 --- a/pages/settings/users/[id].js +++ b/src/pages/settings/users/[id].js @@ -2,7 +2,7 @@ import AppLayout from 'components/layout/AppLayout'; import SettingsLayout from 'components/layout/SettingsLayout'; import UserSettings from 'components/pages/settings/users/UserSettings'; import { useRouter } from 'next/router'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export default function ({ disabled }) { const router = useRouter(); diff --git a/pages/settings/users/index.js b/src/pages/settings/users/index.js similarity index 91% rename from pages/settings/users/index.js rename to src/pages/settings/users/index.js index ee325adc..90026d87 100644 --- a/pages/settings/users/index.js +++ b/src/pages/settings/users/index.js @@ -1,7 +1,7 @@ import AppLayout from 'components/layout/AppLayout'; import SettingsLayout from 'components/layout/SettingsLayout'; import UsersList from 'components/pages/settings/users/UsersList'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export default function ({ disabled }) { const { formatMessage, labels } = useMessages(); diff --git a/pages/settings/websites/[id].js b/src/pages/settings/websites/[id].js similarity index 93% rename from pages/settings/websites/[id].js rename to src/pages/settings/websites/[id].js index f828369e..506da107 100644 --- a/pages/settings/websites/[id].js +++ b/src/pages/settings/websites/[id].js @@ -2,7 +2,7 @@ import AppLayout from 'components/layout/AppLayout'; import { useRouter } from 'next/router'; import WebsiteSettings from 'components/pages/settings/websites/WebsiteSettings'; import SettingsLayout from 'components/layout/SettingsLayout'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export default function ({ disabled }) { const router = useRouter(); diff --git a/pages/settings/websites/index.js b/src/pages/settings/websites/index.js similarity index 92% rename from pages/settings/websites/index.js rename to src/pages/settings/websites/index.js index 899ad7c7..f4551f4a 100644 --- a/pages/settings/websites/index.js +++ b/src/pages/settings/websites/index.js @@ -1,7 +1,7 @@ import AppLayout from 'components/layout/AppLayout'; import SettingsLayout from 'components/layout/SettingsLayout'; import WebsitesList from 'components/pages/settings/websites/WebsitesList'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export default function ({ disabled }) { const { formatMessage, labels } = useMessages(); diff --git a/pages/share/[...id].js b/src/pages/share/[...id].js similarity index 89% rename from pages/share/[...id].js rename to src/pages/share/[...id].js index 1e424382..a2c69df8 100644 --- a/pages/share/[...id].js +++ b/src/pages/share/[...id].js @@ -1,7 +1,7 @@ import { useRouter } from 'next/router'; import ShareLayout from 'components/layout/ShareLayout'; import WebsiteDetailsPage from 'components/pages/websites/WebsiteDetailsPage'; -import useShareToken from 'hooks/useShareToken'; +import useShareToken from 'components/hooks/useShareToken'; export default function () { const router = useRouter(); diff --git a/pages/sso.js b/src/pages/sso.js similarity index 100% rename from pages/sso.js rename to src/pages/sso.js diff --git a/pages/websites/[id]/event-data.js b/src/pages/websites/[id]/event-data.js similarity index 89% rename from pages/websites/[id]/event-data.js rename to src/pages/websites/[id]/event-data.js index 8b44616d..b99d2fc9 100644 --- a/pages/websites/[id]/event-data.js +++ b/src/pages/websites/[id]/event-data.js @@ -1,7 +1,7 @@ import { useRouter } from 'next/router'; import AppLayout from 'components/layout/AppLayout'; import WebsiteEventDataPage from 'components/pages/websites/WebsiteEventDataPage'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export default function () { const { formatMessage, labels } = useMessages(); diff --git a/pages/websites/[id]/index.js b/src/pages/websites/[id]/index.js similarity index 89% rename from pages/websites/[id]/index.js rename to src/pages/websites/[id]/index.js index bec7a45f..d3ec5f93 100644 --- a/pages/websites/[id]/index.js +++ b/src/pages/websites/[id]/index.js @@ -1,7 +1,7 @@ import { useRouter } from 'next/router'; import AppLayout from 'components/layout/AppLayout'; import WebsiteDetailsPage from 'components/pages/websites/WebsiteDetailsPage'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export default function () { const { formatMessage, labels } = useMessages(); diff --git a/pages/websites/[id]/realtime.js b/src/pages/websites/[id]/realtime.js similarity index 100% rename from pages/websites/[id]/realtime.js rename to src/pages/websites/[id]/realtime.js diff --git a/pages/websites/[id]/reports.js b/src/pages/websites/[id]/reports.js similarity index 100% rename from pages/websites/[id]/reports.js rename to src/pages/websites/[id]/reports.js diff --git a/pages/websites/index.js b/src/pages/websites/index.js similarity index 84% rename from pages/websites/index.js rename to src/pages/websites/index.js index 42a327bc..43eed640 100644 --- a/pages/websites/index.js +++ b/src/pages/websites/index.js @@ -1,6 +1,6 @@ import AppLayout from 'components/layout/AppLayout'; import WebsitesPage from 'components/pages/websites/WebsitesPage'; -import useMessages from 'hooks/useMessages'; +import useMessages from 'components/hooks/useMessages'; export default function () { const { formatMessage, labels } = useMessages(); diff --git a/queries/admin/report.ts b/src/queries/admin/report.ts similarity index 100% rename from queries/admin/report.ts rename to src/queries/admin/report.ts diff --git a/queries/admin/team.ts b/src/queries/admin/team.ts similarity index 100% rename from queries/admin/team.ts rename to src/queries/admin/team.ts diff --git a/queries/admin/teamUser.ts b/src/queries/admin/teamUser.ts similarity index 100% rename from queries/admin/teamUser.ts rename to src/queries/admin/teamUser.ts diff --git a/queries/admin/teamWebsite.ts b/src/queries/admin/teamWebsite.ts similarity index 100% rename from queries/admin/teamWebsite.ts rename to src/queries/admin/teamWebsite.ts diff --git a/queries/admin/user.ts b/src/queries/admin/user.ts similarity index 94% rename from queries/admin/user.ts rename to src/queries/admin/user.ts index dfb923f3..dfe8ea28 100644 --- a/queries/admin/user.ts +++ b/src/queries/admin/user.ts @@ -37,10 +37,10 @@ export async function getUserByUsername(username: string, options: GetUserOption } export async function getUsers( - UserSearchFilter: UserSearchFilter = {}, + searchFilter: UserSearchFilter, options?: { include?: Prisma.UserInclude }, ): Promise> { - const { teamId, filter, filterType = USER_FILTER_TYPES.all } = UserSearchFilter; + const { teamId, filter, filterType = USER_FILTER_TYPES.all } = searchFilter; const mode = prisma.getSearchMode(); const where: Prisma.UserWhereInput = { @@ -67,19 +67,25 @@ export async function getUsers( }, }), }; + const [pageFilters, getParameters] = prisma.getPageFilters({ orderBy: 'username', - ...UserSearchFilter, + ...searchFilter, }); - const users = await prisma.client.user.findMany({ - where: { - ...where, - deletedAt: null, - }, - ...pageFilters, - ...(options?.include && { include: options.include }), - }); + const users = await prisma.client.user + .findMany({ + where: { + ...where, + deletedAt: null, + }, + ...pageFilters, + ...(options?.include && { include: options.include }), + }) + .then(a => { + return a.map(({ password, ...rest }) => rest); + }); + const count = await prisma.client.user.count({ where: { ...where, diff --git a/queries/admin/website.ts b/src/queries/admin/website.ts similarity index 100% rename from queries/admin/website.ts rename to src/queries/admin/website.ts diff --git a/queries/analytics/eventData/getEventDataEvents.ts b/src/queries/analytics/eventData/getEventDataEvents.ts similarity index 100% rename from queries/analytics/eventData/getEventDataEvents.ts rename to src/queries/analytics/eventData/getEventDataEvents.ts diff --git a/queries/analytics/eventData/getEventDataFields.ts b/src/queries/analytics/eventData/getEventDataFields.ts similarity index 100% rename from queries/analytics/eventData/getEventDataFields.ts rename to src/queries/analytics/eventData/getEventDataFields.ts diff --git a/queries/analytics/eventData/getEventDataStats.ts b/src/queries/analytics/eventData/getEventDataStats.ts similarity index 100% rename from queries/analytics/eventData/getEventDataStats.ts rename to src/queries/analytics/eventData/getEventDataStats.ts diff --git a/queries/analytics/eventData/getEventDataUsage.ts b/src/queries/analytics/eventData/getEventDataUsage.ts similarity index 100% rename from queries/analytics/eventData/getEventDataUsage.ts rename to src/queries/analytics/eventData/getEventDataUsage.ts diff --git a/queries/analytics/eventData/saveEventData.ts b/src/queries/analytics/eventData/saveEventData.ts similarity index 100% rename from queries/analytics/eventData/saveEventData.ts rename to src/queries/analytics/eventData/saveEventData.ts diff --git a/queries/analytics/events/getEventMetrics.ts b/src/queries/analytics/events/getEventMetrics.ts similarity index 100% rename from queries/analytics/events/getEventMetrics.ts rename to src/queries/analytics/events/getEventMetrics.ts diff --git a/queries/analytics/events/getEventUsage.ts b/src/queries/analytics/events/getEventUsage.ts similarity index 100% rename from queries/analytics/events/getEventUsage.ts rename to src/queries/analytics/events/getEventUsage.ts diff --git a/queries/analytics/events/getEvents.ts b/src/queries/analytics/events/getEvents.ts similarity index 100% rename from queries/analytics/events/getEvents.ts rename to src/queries/analytics/events/getEvents.ts diff --git a/queries/analytics/events/saveEvent.ts b/src/queries/analytics/events/saveEvent.ts similarity index 100% rename from queries/analytics/events/saveEvent.ts rename to src/queries/analytics/events/saveEvent.ts diff --git a/queries/analytics/getActiveVisitors.ts b/src/queries/analytics/getActiveVisitors.ts similarity index 100% rename from queries/analytics/getActiveVisitors.ts rename to src/queries/analytics/getActiveVisitors.ts diff --git a/queries/analytics/getRealtimeData.ts b/src/queries/analytics/getRealtimeData.ts similarity index 100% rename from queries/analytics/getRealtimeData.ts rename to src/queries/analytics/getRealtimeData.ts diff --git a/queries/analytics/getValues.ts b/src/queries/analytics/getValues.ts similarity index 100% rename from queries/analytics/getValues.ts rename to src/queries/analytics/getValues.ts diff --git a/queries/analytics/getWebsiteDateRange.ts b/src/queries/analytics/getWebsiteDateRange.ts similarity index 100% rename from queries/analytics/getWebsiteDateRange.ts rename to src/queries/analytics/getWebsiteDateRange.ts diff --git a/queries/analytics/getWebsiteStats.ts b/src/queries/analytics/getWebsiteStats.ts similarity index 100% rename from queries/analytics/getWebsiteStats.ts rename to src/queries/analytics/getWebsiteStats.ts diff --git a/queries/analytics/pageviews/getPageviewMetrics.ts b/src/queries/analytics/pageviews/getPageviewMetrics.ts similarity index 100% rename from queries/analytics/pageviews/getPageviewMetrics.ts rename to src/queries/analytics/pageviews/getPageviewMetrics.ts diff --git a/queries/analytics/pageviews/getPageviewStats.ts b/src/queries/analytics/pageviews/getPageviewStats.ts similarity index 100% rename from queries/analytics/pageviews/getPageviewStats.ts rename to src/queries/analytics/pageviews/getPageviewStats.ts diff --git a/queries/analytics/reports/getFunnel.ts b/src/queries/analytics/reports/getFunnel.ts similarity index 100% rename from queries/analytics/reports/getFunnel.ts rename to src/queries/analytics/reports/getFunnel.ts diff --git a/queries/analytics/reports/getInsights.ts b/src/queries/analytics/reports/getInsights.ts similarity index 100% rename from queries/analytics/reports/getInsights.ts rename to src/queries/analytics/reports/getInsights.ts diff --git a/queries/analytics/reports/getRetention.ts b/src/queries/analytics/reports/getRetention.ts similarity index 100% rename from queries/analytics/reports/getRetention.ts rename to src/queries/analytics/reports/getRetention.ts diff --git a/queries/analytics/sessions/createSession.ts b/src/queries/analytics/sessions/createSession.ts similarity index 100% rename from queries/analytics/sessions/createSession.ts rename to src/queries/analytics/sessions/createSession.ts diff --git a/queries/analytics/sessions/getSession.ts b/src/queries/analytics/sessions/getSession.ts similarity index 100% rename from queries/analytics/sessions/getSession.ts rename to src/queries/analytics/sessions/getSession.ts diff --git a/queries/analytics/sessions/getSessionMetrics.ts b/src/queries/analytics/sessions/getSessionMetrics.ts similarity index 100% rename from queries/analytics/sessions/getSessionMetrics.ts rename to src/queries/analytics/sessions/getSessionMetrics.ts diff --git a/queries/analytics/sessions/getSessionStats.ts b/src/queries/analytics/sessions/getSessionStats.ts similarity index 100% rename from queries/analytics/sessions/getSessionStats.ts rename to src/queries/analytics/sessions/getSessionStats.ts diff --git a/queries/analytics/sessions/getSessions.ts b/src/queries/analytics/sessions/getSessions.ts similarity index 100% rename from queries/analytics/sessions/getSessions.ts rename to src/queries/analytics/sessions/getSessions.ts diff --git a/queries/analytics/sessions/saveSessionData.ts b/src/queries/analytics/sessions/saveSessionData.ts similarity index 100% rename from queries/analytics/sessions/saveSessionData.ts rename to src/queries/analytics/sessions/saveSessionData.ts diff --git a/queries/index.js b/src/queries/index.js similarity index 100% rename from queries/index.js rename to src/queries/index.js diff --git a/store/app.js b/src/store/app.js similarity index 100% rename from store/app.js rename to src/store/app.js diff --git a/store/dashboard.js b/src/store/dashboard.js similarity index 100% rename from store/dashboard.js rename to src/store/dashboard.js diff --git a/store/queries.js b/src/store/queries.js similarity index 100% rename from store/queries.js rename to src/store/queries.js diff --git a/store/version.js b/src/store/version.js similarity index 97% rename from store/version.js rename to src/store/version.js index c232c7fa..3b5afaac 100644 --- a/store/version.js +++ b/src/store/version.js @@ -1,5 +1,5 @@ import { create } from 'zustand'; -import produce from 'immer'; +import { produce } from 'immer'; import semver from 'semver'; import { CURRENT_VERSION, VERSION_CHECK, UPDATES_URL } from 'lib/constants'; import { getItem } from 'next-basics'; diff --git a/store/websites.ts b/src/store/websites.ts similarity index 94% rename from store/websites.ts rename to src/store/websites.ts index 0d210af6..5d0eeccd 100644 --- a/store/websites.ts +++ b/src/store/websites.ts @@ -1,5 +1,5 @@ import { create } from 'zustand'; -import produce from 'immer'; +import { produce } from 'immer'; import { DateRange } from 'lib/types'; const store = create(() => ({})); diff --git a/styles/index.css b/src/styles/index.css similarity index 100% rename from styles/index.css rename to src/styles/index.css diff --git a/styles/locale.css b/src/styles/locale.css similarity index 100% rename from styles/locale.css rename to src/styles/locale.css diff --git a/styles/variables.css b/src/styles/variables.css similarity index 100% rename from styles/variables.css rename to src/styles/variables.css diff --git a/tracker/index.d.ts b/src/tracker/index.d.ts similarity index 100% rename from tracker/index.d.ts rename to src/tracker/index.d.ts diff --git a/tracker/index.js b/src/tracker/index.js similarity index 100% rename from tracker/index.js rename to src/tracker/index.js diff --git a/tsconfig.json b/tsconfig.json index b022d603..71094dd7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,7 +6,6 @@ "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, - "incremental": true, "lib": ["dom", "dom.iterable", "esnext"], "skipLibCheck": true, "esModuleInterop": true, @@ -18,11 +17,21 @@ "forceConsistentCasingInFileNames": true, "allowJs": true, "strict": true, - "baseUrl": ".", "strictNullChecks": false, "noEmit": true, - "jsx": "preserve" + "jsx": "preserve", + "incremental": false, + "baseUrl": "./src", + "paths": { + "assets/*": ["./assets/*"], + "components/*": ["./components/*"], + "lib/*": ["./lib/*"], + "pages/*": ["./pages/*"], + "queries/*": ["./queries/*"], + "store/*": ["./store/*"], + "styles/*": ["./styles/*"] + } }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "include": ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", "next-env.d.ts"], "exclude": ["node_modules"] } diff --git a/yarn.lock b/yarn.lock index e18f833c..c20730f3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15,7 +15,7 @@ "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.18.6", "@babel/code-frame@^7.22.5": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.22.5": version "7.22.5" resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz" integrity sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ== @@ -1550,7 +1550,7 @@ resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== -"@jridgewell/sourcemap-codec@^1.4.13": +"@jridgewell/sourcemap-codec@^1.4.13", "@jridgewell/sourcemap-codec@^1.4.15": version "1.4.15" resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== @@ -1754,10 +1754,10 @@ slash "^3.0.0" tiny-glob "^0.2.9" -"@next/env@13.3.1": - version "13.3.1" - resolved "https://registry.yarnpkg.com/@next/env/-/env-13.3.1.tgz#589707043065f6b71d411ed9b8f1ffd057c0fd4a" - integrity sha512-EDtCoedIZC7JlUQ3uaQpSc4aVmyhbLHmQVALg7pFfQgOTjgSnn7mKtA0DiCMkYvvsx6aFb5octGMtWrOtGXW9A== +"@next/env@13.4.19": + version "13.4.19" + resolved "https://registry.yarnpkg.com/@next/env/-/env-13.4.19.tgz#46905b4e6f62da825b040343cbc233144e9578d3" + integrity sha512-FsAT5x0jF2kkhNkKkukhsyYOrRqtSxrEhfliniIq0bwWbuXLgyt3Gv0Ml+b91XwjwArmuP7NxCiGd++GGKdNMQ== "@next/eslint-plugin-next@12.3.4": version "12.3.4" @@ -1766,50 +1766,50 @@ dependencies: glob "7.1.7" -"@next/swc-darwin-arm64@13.3.1": - version "13.3.1" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.3.1.tgz#2c9719dd10a9cdf63bf50a7576b05dcf78999fe8" - integrity sha512-UXPtriEc/pBP8luSLSCZBcbzPeVv+SSjs9cH/KygTbhmACye8/OOXRZO13Z2Wq1G0gLmEAIHQAOuF+vafPd2lw== +"@next/swc-darwin-arm64@13.4.19": + version "13.4.19" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.19.tgz#77ad462b5ced4efdc26cb5a0053968d2c7dac1b6" + integrity sha512-vv1qrjXeGbuF2mOkhkdxMDtv9np7W4mcBtaDnHU+yJG+bBwa6rYsYSCI/9Xm5+TuF5SbZbrWO6G1NfTh1TMjvQ== -"@next/swc-darwin-x64@13.3.1": - version "13.3.1" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.3.1.tgz#0be90342c89e53a390ccd9bece15f7f5cd480049" - integrity sha512-lT36yYxosCfLtplFzJWgo0hrPu6/do8+msgM7oQkPeohDNdhjtjFUgOOwdSnPublLR6Mo2Ym4P/wl5OANuD2bw== +"@next/swc-darwin-x64@13.4.19": + version "13.4.19" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.19.tgz#aebe38713a4ce536ee5f2a291673e14b715e633a" + integrity sha512-jyzO6wwYhx6F+7gD8ddZfuqO4TtpJdw3wyOduR4fxTUCm3aLw7YmHGYNjS0xRSYGAkLpBkH1E0RcelyId6lNsw== -"@next/swc-linux-arm64-gnu@13.3.1": - version "13.3.1" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.3.1.tgz#a7353265839f8b8569a346a444dc3ab3770d297e" - integrity sha512-wRb76nLWJhonH8s3kxC/1tFguEkeOPayIwe9mkaz1G/yeS3OrjeyKMJsb4+Kdg0zbTo53bNCOl59NNtDM7yyyw== +"@next/swc-linux-arm64-gnu@13.4.19": + version "13.4.19" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.19.tgz#ec54db65b587939c7b94f9a84800f003a380f5a6" + integrity sha512-vdlnIlaAEh6H+G6HrKZB9c2zJKnpPVKnA6LBwjwT2BTjxI7e0Hx30+FoWCgi50e+YO49p6oPOtesP9mXDRiiUg== -"@next/swc-linux-arm64-musl@13.3.1": - version "13.3.1" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.3.1.tgz#24552e6102c350e372f83f505a1d93c880551a50" - integrity sha512-qz3BzjJRZ16Iq/jrp+pjiYOc0jTjHlfmxQmZk9x/+5uhRP6/eWQSTAPVJ33BMo6oK5O5N4644OgTAbzXzorecg== +"@next/swc-linux-arm64-musl@13.4.19": + version "13.4.19" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.19.tgz#1f5e2c1ea6941e7d530d9f185d5d64be04279d86" + integrity sha512-aU0HkH2XPgxqrbNRBFb3si9Ahu/CpaR5RPmN2s9GiM9qJCiBBlZtRTiEca+DC+xRPyCThTtWYgxjWHgU7ZkyvA== -"@next/swc-linux-x64-gnu@13.3.1": - version "13.3.1" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.3.1.tgz#5f335a683b6eafa52307b12af97782993b6c45ff" - integrity sha512-6mgkLmwlyWlomQmpl21I3hxgqE5INoW4owTlcLpNsd1V4wP+J46BlI/5zV5KWWbzjfncIqzXoeGs5Eg+1GHODA== +"@next/swc-linux-x64-gnu@13.4.19": + version "13.4.19" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.19.tgz#96b0882492a2f7ffcce747846d3680730f69f4d1" + integrity sha512-htwOEagMa/CXNykFFeAHHvMJeqZfNQEoQvHfsA4wgg5QqGNqD5soeCer4oGlCol6NGUxknrQO6VEustcv+Md+g== -"@next/swc-linux-x64-musl@13.3.1": - version "13.3.1" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.3.1.tgz#58e5aad6f97203a0788783f66324456c8f9cdb50" - integrity sha512-uqm5sielhQmKJM+qayIhgZv1KlS5pqTdQ99b+Z7hMWryXS96qE0DftTmMZowBcUL6x7s2vSXyH5wPtO1ON7LBg== +"@next/swc-linux-x64-musl@13.4.19": + version "13.4.19" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.19.tgz#f276b618afa321d2f7b17c81fc83f429fb0fd9d8" + integrity sha512-4Gj4vvtbK1JH8ApWTT214b3GwUh9EKKQjY41hH/t+u55Knxi/0wesMzwQRhppK6Ddalhu0TEttbiJ+wRcoEj5Q== -"@next/swc-win32-arm64-msvc@13.3.1": - version "13.3.1" - resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.3.1.tgz#f8ed1badab57ed4503969758754e6fb0cf326753" - integrity sha512-WomIiTj/v3LevltlibNQKmvrOymNRYL+a0dp5R73IwPWN5FvXWwSELN/kiNALig/+T3luc4qHNTyvMCp9L6U5Q== +"@next/swc-win32-arm64-msvc@13.4.19": + version "13.4.19" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.19.tgz#1599ae0d401da5ffca0947823dac577697cce577" + integrity sha512-bUfDevQK4NsIAHXs3/JNgnvEY+LRyneDN788W2NYiRIIzmILjba7LaQTfihuFawZDhRtkYCv3JDC3B4TwnmRJw== -"@next/swc-win32-ia32-msvc@13.3.1": - version "13.3.1" - resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.3.1.tgz#7f599c8975b09ee5527cc49b9e5a4d13be50635a" - integrity sha512-M+PoH+0+q658wRUbs285RIaSTYnGBSTdweH/0CdzDgA6Q4rBM0sQs4DHmO3BPP0ltCO/vViIoyG7ks66XmCA5g== +"@next/swc-win32-ia32-msvc@13.4.19": + version "13.4.19" + resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.19.tgz#55cdd7da90818f03e4da16d976f0cb22045d16fd" + integrity sha512-Y5kikILFAr81LYIFaw6j/NrOtmiM4Sf3GtOc0pn50ez2GCkr+oejYuKGcwAwq3jiTKuzF6OF4iT2INPoxRycEA== -"@next/swc-win32-x64-msvc@13.3.1": - version "13.3.1" - resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.3.1.tgz#192d43ab44ebb98bd4f5865d0e1d7ce62703182f" - integrity sha512-Sl1F4Vp5Z1rNXWZYqJwMuWRRol4bqOB6+/d7KqkgQ4AcafKPN1PZmpkCoxv4UFHtFNIB7EotnuIhtXu3zScicQ== +"@next/swc-win32-x64-msvc@13.4.19": + version "13.4.19" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.19.tgz#648f79c4e09279212ac90d871646ae12d80cdfce" + integrity sha512-YzA78jBDXMYiINdPdJJwGgPNT3YqBNNGhsthsDoWHL9p24tEJn9ViQf/ZqTbwSpX/RrkPupLfuuTH2sf73JBAw== "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -1969,19 +1969,19 @@ dependencies: slash "^4.0.0" -"@rollup/plugin-buble@^0.21.3": - version "0.21.3" - resolved "https://registry.npmjs.org/@rollup/plugin-buble/-/plugin-buble-0.21.3.tgz" - integrity sha512-Iv8cCuFPnMdqV4pcyU+OrfjOfagPArRQ1PyQjx5KgHk3dARedI+8PNTLSMpJts0lQJr8yF2pAU4GxpxCBJ9HYw== +"@rollup/plugin-buble@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@rollup/plugin-buble/-/plugin-buble-1.0.2.tgz#30af390341b0888490f781fcf17e469198d118a2" + integrity sha512-Hz9+AigRWwS93vmorrVrhyG9SdSCZAkBDx614w09iFQYFUAP2HmdUrQyZsb1WO2n+iDvPFznrTE16la+eGNcEQ== dependencies: - "@rollup/pluginutils" "^3.0.8" + "@rollup/pluginutils" "^5.0.1" "@types/buble" "^0.19.2" buble "^0.20.0" -"@rollup/plugin-commonjs@^24.1.0": - version "24.1.0" - resolved "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-24.1.0.tgz" - integrity sha512-eSL45hjhCWI0jCCXcNtLVqM5N1JlBGvlFfY0m6oOYnLCJ6N0qEXoZql4sY2MOUArzhH4SA/qBpTxvvZp2Sc+DQ== +"@rollup/plugin-commonjs@^25.0.4": + version "25.0.4" + resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.4.tgz#a7547a0c4ec3fa79818eb313e1de0023e548f4e6" + integrity sha512-L92Vz9WUZXDnlQQl3EwbypJR4+DM2EbsO+/KOcEkP4Mc6Ct453EeDB2uH9lgRwj4w5yflgNpq9pHOiY8aoUXBQ== dependencies: "@rollup/pluginutils" "^5.0.1" commondir "^1.0.1" @@ -1992,15 +1992,15 @@ "@rollup/plugin-json@^6.0.0": version "6.0.0" - resolved "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.0.0.tgz" + resolved "https://registry.yarnpkg.com/@rollup/plugin-json/-/plugin-json-6.0.0.tgz#199fea6670fd4dfb1f4932250569b14719db234a" integrity sha512-i/4C5Jrdr1XUarRhVu27EEwjt4GObltD7c+MkCIpO2QIbojw8MUs+CCTqOphQi3Qtg1FLmYt+l+6YeoIf51J7w== dependencies: "@rollup/pluginutils" "^5.0.1" -"@rollup/plugin-node-resolve@^15.0.2": - version "15.1.0" - resolved "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.1.0.tgz" - integrity sha512-xeZHCgsiZ9pzYVgAo9580eCGqwh/XCEUM9q6iQfGNocjgkufHAqC3exA+45URvhiYV8sBF9RlBai650eNs7AsA== +"@rollup/plugin-node-resolve@^15.2.0": + version "15.2.0" + resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.0.tgz#982053b237f81471aace570472e88a456d211621" + integrity sha512-mKur03xNGT8O9ODO6FtT43ITGqHWZbKPdVJHZb+iV9QYcdlhUUB0wgknvA4KCUmC5oHJF6O2W1EgmyOQyVUI4Q== dependencies: "@rollup/pluginutils" "^5.0.1" "@types/resolve" "1.20.2" @@ -2009,22 +2009,13 @@ is-module "^1.0.0" resolve "^1.22.1" -"@rollup/plugin-replace@^4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-4.0.0.tgz" - integrity sha512-+rumQFiaNac9y64OHtkHGmdjm7us9bo1PlbgQfdihQtuNxzjpaB064HbRnewUOggLQxVCCyINfStkgmBeQpv1g== +"@rollup/plugin-replace@^5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@rollup/plugin-replace/-/plugin-replace-5.0.2.tgz#45f53501b16311feded2485e98419acb8448c61d" + integrity sha512-M9YXNekv/C/iHHK+cvORzfRYfPbq0RDD8r0G+bMiTXjNGKulPnCT9O3Ss46WfhI6ZOCgApOP7xAdmCQJ+U2LAA== dependencies: - "@rollup/pluginutils" "^3.1.0" - magic-string "^0.25.7" - -"@rollup/pluginutils@^3.0.8", "@rollup/pluginutils@^3.1.0": - version "3.1.0" - resolved "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz" - integrity sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg== - dependencies: - "@types/estree" "0.0.39" - estree-walker "^1.0.1" - picomatch "^2.2.2" + "@rollup/pluginutils" "^5.0.1" + magic-string "^0.27.0" "@rollup/pluginutils@^5.0.1", "@rollup/pluginutils@^5.0.2": version "5.0.2" @@ -2040,75 +2031,99 @@ resolved "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz" integrity sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg== +"@svgr/babel-plugin-add-jsx-attribute@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz#4001f5d5dd87fa13303e36ee106e3ff3a7eb8b22" + integrity sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g== + "@svgr/babel-plugin-add-jsx-attribute@^6.5.1": version "6.5.1" resolved "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-6.5.1.tgz" integrity sha512-9PYGcXrAxitycIjRmZB+Q0JaN07GZIWaTBIGQzfaZv+qr1n8X1XUEJ5rZ/vx6OVD9RRYlrNnXWExQXcmZeD/BQ== -"@svgr/babel-plugin-add-jsx-attribute@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-7.0.0.tgz" - integrity sha512-khWbXesWIP9v8HuKCl2NU2HNAyqpSQ/vkIl36Nbn4HIwEYSRWL0H7Gs6idJdha2DkpFDWlsqMELvoCE8lfFY6Q== - -"@svgr/babel-plugin-remove-jsx-attribute@*", "@svgr/babel-plugin-remove-jsx-attribute@^7.0.0": +"@svgr/babel-plugin-remove-jsx-attribute@*": version "7.0.0" resolved "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-7.0.0.tgz" integrity sha512-iiZaIvb3H/c7d3TH2HBeK91uI2rMhZNwnsIrvd7ZwGLkFw6mmunOCoVnjdYua662MqGFxlN9xTq4fv9hgR4VXQ== -"@svgr/babel-plugin-remove-jsx-empty-expression@*", "@svgr/babel-plugin-remove-jsx-empty-expression@^7.0.0": +"@svgr/babel-plugin-remove-jsx-attribute@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz#69177f7937233caca3a1afb051906698f2f59186" + integrity sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA== + +"@svgr/babel-plugin-remove-jsx-empty-expression@*": version "7.0.0" resolved "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-7.0.0.tgz" integrity sha512-sQQmyo+qegBx8DfFc04PFmIO1FP1MHI1/QEpzcIcclo5OAISsOJPW76ZIs0bDyO/DBSJEa/tDa1W26pVtt0FRw== +"@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz#c2c48104cfd7dcd557f373b70a56e9e3bdae1d44" + integrity sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA== + +"@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz#8fbb6b2e91fa26ac5d4aa25c6b6e4f20f9c0ae27" + integrity sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ== + "@svgr/babel-plugin-replace-jsx-attribute-value@^6.5.1": version "6.5.1" resolved "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-6.5.1.tgz" integrity sha512-8DPaVVE3fd5JKuIC29dqyMB54sA6mfgki2H2+swh+zNJoynC8pMPzOkidqHOSc6Wj032fhl8Z0TVn1GiPpAiJg== -"@svgr/babel-plugin-replace-jsx-attribute-value@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-7.0.0.tgz" - integrity sha512-i6MaAqIZXDOJeikJuzocByBf8zO+meLwfQ/qMHIjCcvpnfvWf82PFvredEZElErB5glQFJa2KVKk8N2xV6tRRA== +"@svgr/babel-plugin-svg-dynamic-title@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz#1d5ba1d281363fc0f2f29a60d6d936f9bbc657b0" + integrity sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og== "@svgr/babel-plugin-svg-dynamic-title@^6.5.1": version "6.5.1" resolved "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-6.5.1.tgz" integrity sha512-FwOEi0Il72iAzlkaHrlemVurgSQRDFbk0OC8dSvD5fSBPHltNh7JtLsxmZUhjYBZo2PpcU/RJvvi6Q0l7O7ogw== -"@svgr/babel-plugin-svg-dynamic-title@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-7.0.0.tgz" - integrity sha512-BoVSh6ge3SLLpKC0pmmN9DFlqgFy4NxNgdZNLPNJWBUU7TQpDWeBuyVuDW88iXydb5Cv0ReC+ffa5h3VrKfk1w== +"@svgr/babel-plugin-svg-em-dimensions@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz#35e08df300ea8b1d41cb8f62309c241b0369e501" + integrity sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g== "@svgr/babel-plugin-svg-em-dimensions@^6.5.1": version "6.5.1" resolved "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-6.5.1.tgz" integrity sha512-gWGsiwjb4tw+ITOJ86ndY/DZZ6cuXMNE/SjcDRg+HLuCmwpcjOktwRF9WgAiycTqJD/QXqL2f8IzE2Rzh7aVXA== -"@svgr/babel-plugin-svg-em-dimensions@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-7.0.0.tgz" - integrity sha512-tNDcBa+hYn0gO+GkP/AuNKdVtMufVhU9fdzu+vUQsR18RIJ9RWe7h/pSBY338RO08wArntwbDk5WhQBmhf2PaA== +"@svgr/babel-plugin-transform-react-native-svg@8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz#90a8b63998b688b284f255c6a5248abd5b28d754" + integrity sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q== "@svgr/babel-plugin-transform-react-native-svg@^6.5.1": version "6.5.1" resolved "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-6.5.1.tgz" integrity sha512-2jT3nTayyYP7kI6aGutkyfJ7UMGtuguD72OjeGLwVNyfPRBD8zQthlvL+fAbAKk5n9ZNcvFkp/b1lZ7VsYqVJg== -"@svgr/babel-plugin-transform-react-native-svg@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-7.0.0.tgz" - integrity sha512-qw54u8ljCJYL2KtBOjI5z7Nzg8LnSvQOP5hPKj77H4VQL4+HdKbAT5pnkkZLmHKYwzsIHSYKXxHouD8zZamCFQ== +"@svgr/babel-plugin-transform-svg-component@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz#013b4bfca88779711f0ed2739f3f7efcefcf4f7e" + integrity sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw== "@svgr/babel-plugin-transform-svg-component@^6.5.1": version "6.5.1" resolved "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-6.5.1.tgz" integrity sha512-a1p6LF5Jt33O3rZoVRBqdxL350oge54iZWHNI6LJB5tQ7EelvD/Mb1mfBiZNAan0dt4i3VArkFRjA4iObuNykQ== -"@svgr/babel-plugin-transform-svg-component@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-7.0.0.tgz" - integrity sha512-CcFECkDj98daOg9jE3Bh3uyD9kzevCAnZ+UtzG6+BQG/jOQ2OA3jHnX6iG4G1MCJkUQFnUvEv33NvQfqrb/F3A== +"@svgr/babel-preset@8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-preset/-/babel-preset-8.1.0.tgz#0e87119aecdf1c424840b9d4565b7137cabf9ece" + integrity sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug== + dependencies: + "@svgr/babel-plugin-add-jsx-attribute" "8.0.0" + "@svgr/babel-plugin-remove-jsx-attribute" "8.0.0" + "@svgr/babel-plugin-remove-jsx-empty-expression" "8.0.0" + "@svgr/babel-plugin-replace-jsx-attribute-value" "8.0.0" + "@svgr/babel-plugin-svg-dynamic-title" "8.0.0" + "@svgr/babel-plugin-svg-em-dimensions" "8.0.0" + "@svgr/babel-plugin-transform-react-native-svg" "8.1.0" + "@svgr/babel-plugin-transform-svg-component" "8.0.0" "@svgr/babel-preset@^6.5.1": version "6.5.1" @@ -2124,19 +2139,16 @@ "@svgr/babel-plugin-transform-react-native-svg" "^6.5.1" "@svgr/babel-plugin-transform-svg-component" "^6.5.1" -"@svgr/babel-preset@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-7.0.0.tgz" - integrity sha512-EX/NHeFa30j5UjldQGVQikuuQNHUdGmbh9kEpBKofGUtF0GUPJ4T4rhoYiqDAOmBOxojyot36JIFiDUHUK1ilQ== +"@svgr/core@8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@svgr/core/-/core-8.1.0.tgz#41146f9b40b1a10beaf5cc4f361a16a3c1885e88" + integrity sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA== dependencies: - "@svgr/babel-plugin-add-jsx-attribute" "^7.0.0" - "@svgr/babel-plugin-remove-jsx-attribute" "^7.0.0" - "@svgr/babel-plugin-remove-jsx-empty-expression" "^7.0.0" - "@svgr/babel-plugin-replace-jsx-attribute-value" "^7.0.0" - "@svgr/babel-plugin-svg-dynamic-title" "^7.0.0" - "@svgr/babel-plugin-svg-em-dimensions" "^7.0.0" - "@svgr/babel-plugin-transform-react-native-svg" "^7.0.0" - "@svgr/babel-plugin-transform-svg-component" "^7.0.0" + "@babel/core" "^7.21.3" + "@svgr/babel-preset" "8.1.0" + camelcase "^6.2.0" + cosmiconfig "^8.1.3" + snake-case "^3.0.4" "@svgr/core@^6.5.1": version "6.5.1" @@ -2149,15 +2161,13 @@ camelcase "^6.2.0" cosmiconfig "^7.0.1" -"@svgr/core@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@svgr/core/-/core-7.0.0.tgz" - integrity sha512-ztAoxkaKhRVloa3XydohgQQCb0/8x9T63yXovpmHzKMkHO6pkjdsIAWKOS4bE95P/2quVh1NtjSKlMRNzSBffw== +"@svgr/hast-util-to-babel-ast@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz#6952fd9ce0f470e1aded293b792a2705faf4ffd4" + integrity sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q== dependencies: - "@babel/core" "^7.21.3" - "@svgr/babel-preset" "^7.0.0" - camelcase "^6.2.0" - cosmiconfig "^8.1.3" + "@babel/types" "^7.21.3" + entities "^4.4.0" "@svgr/hast-util-to-babel-ast@^6.5.1": version "6.5.1" @@ -2167,13 +2177,15 @@ "@babel/types" "^7.20.0" entities "^4.4.0" -"@svgr/hast-util-to-babel-ast@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-7.0.0.tgz" - integrity sha512-42Ej9sDDEmsJKjrfQ1PHmiDiHagh/u9AHO9QWbeNx4KmD9yS5d1XHmXUNINfUcykAU+4431Cn+k6Vn5mWBYimQ== +"@svgr/plugin-jsx@8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz#96969f04a24b58b174ee4cd974c60475acbd6928" + integrity sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA== dependencies: - "@babel/types" "^7.21.3" - entities "^4.4.0" + "@babel/core" "^7.21.3" + "@svgr/babel-preset" "8.1.0" + "@svgr/hast-util-to-babel-ast" "8.0.0" + svg-parser "^2.0.4" "@svgr/plugin-jsx@^6.5.1": version "6.5.1" @@ -2185,15 +2197,14 @@ "@svgr/hast-util-to-babel-ast" "^6.5.1" svg-parser "^2.0.4" -"@svgr/plugin-jsx@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-7.0.0.tgz" - integrity sha512-SWlTpPQmBUtLKxXWgpv8syzqIU8XgFRvyhfkam2So8b3BE0OS0HPe5UfmlJ2KIC+a7dpuuYovPR2WAQuSyMoPw== +"@svgr/plugin-svgo@8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@svgr/plugin-svgo/-/plugin-svgo-8.1.0.tgz#b115b7b967b564f89ac58feae89b88c3decd0f00" + integrity sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA== dependencies: - "@babel/core" "^7.21.3" - "@svgr/babel-preset" "^7.0.0" - "@svgr/hast-util-to-babel-ast" "^7.0.0" - svg-parser "^2.0.4" + cosmiconfig "^8.1.3" + deepmerge "^4.3.1" + svgo "^3.0.2" "@svgr/plugin-svgo@^6.5.1": version "6.5.1" @@ -2204,19 +2215,10 @@ deepmerge "^4.2.2" svgo "^2.8.0" -"@svgr/plugin-svgo@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-7.0.0.tgz" - integrity sha512-263znzlu3qTKj71/ot5G9l2vpL4CW+pr2IexBFIwwB+fRAXE9Xnw2rUFgE6P4+37N9siOuC4lKkgBfUCOLFRKQ== - dependencies: - cosmiconfig "^8.1.3" - deepmerge "^4.3.1" - svgo "^3.0.2" - -"@svgr/rollup@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@svgr/rollup/-/rollup-7.0.0.tgz" - integrity sha512-zlx0lxtxTnrXFF+ISuff+hht2XcWXa6uXEliwQbz+o0/qRIrcqyB9ShalO9ekVWB5icgxCWQ5lDaULJTt/pTlA== +"@svgr/rollup@^8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@svgr/rollup/-/rollup-8.1.0.tgz#2c8e09655336cda4b7843799a5d2a5860300b030" + integrity sha512-0XR1poYvPQoPpmfDYLEqUGu5ePAQ4pdgN3VFsZBNAeze7qubVpsIY1o1R6PZpKep/DKu33GSm2NhwpCLkMs2Cw== dependencies: "@babel/core" "^7.21.3" "@babel/plugin-transform-react-constant-elements" "^7.21.3" @@ -2224,9 +2226,9 @@ "@babel/preset-react" "^7.18.6" "@babel/preset-typescript" "^7.21.0" "@rollup/pluginutils" "^5.0.2" - "@svgr/core" "^7.0.0" - "@svgr/plugin-jsx" "^7.0.0" - "@svgr/plugin-svgo" "^7.0.0" + "@svgr/core" "8.1.0" + "@svgr/plugin-jsx" "8.1.0" + "@svgr/plugin-svgo" "8.1.0" "@svgr/webpack@^6.2.1": version "6.5.1" @@ -2242,24 +2244,24 @@ "@svgr/plugin-jsx" "^6.5.1" "@svgr/plugin-svgo" "^6.5.1" -"@swc/helpers@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.0.tgz#bf1d807b60f7290d0ec763feea7ccdeda06e85f1" - integrity sha512-SjY/p4MmECVVEWspzSRpQEM3sjR17sP8PbGxELWrT+YZMBfiUyt1MRUNjMV23zohwlG2HYtCQOsCwsTHguXkyg== +"@swc/helpers@0.5.1": + version "0.5.1" + resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.1.tgz#e9031491aa3f26bfcc974a67f48bd456c8a5357a" + integrity sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg== dependencies: tslib "^2.4.0" -"@tanstack/query-core@4.32.0": - version "4.32.0" - resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-4.32.0.tgz#e0f4a830283612430450c13badd353766423f523" - integrity sha512-ei4IYwL2kmlKSlCw9WgvV7PpXi0MiswVwfQRxawhJA690zWO3dU49igaQ/UMTl+Jy9jj9dK5IKAYvbX7kUvviQ== +"@tanstack/query-core@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-4.33.0.tgz#7756da9a75a424e521622b1d84eb55b7a2b33715" + integrity sha512-qYu73ptvnzRh6se2nyBIDHGBQvPY1XXl3yR769B7B6mIDD7s+EZhdlWHQ67JI6UOTFRaI7wupnTnwJ3gE0Mr/g== -"@tanstack/react-query@^4.16.1": - version "4.32.0" - resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-4.32.0.tgz#701b45b149cfd4b54a68705f9100973db3ba5d5d" - integrity sha512-B8WUMcByYAH9500ENejDCATOmEZhqjtS9wsfiQ3BNa+s+yAynY8SESI8WWHhSqUmjd0pmCSFRP6BOUGSda3QXA== +"@tanstack/react-query@^4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-4.33.0.tgz#e927b0343a6ecaa948fee59e9ca98fe561062638" + integrity sha512-97nGbmDK0/m0B86BdiXzx3EW9RcDYKpnyL2+WwyuLHEgpfThYAnXFaMMmnTDuAO4bQJXEhflumIEUfKmP7ESGA== dependencies: - "@tanstack/query-core" "4.32.0" + "@tanstack/query-core" "4.33.0" use-sync-external-store "^1.2.0" "@trysound/sax@0.2.0": @@ -2332,16 +2334,18 @@ resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz" integrity sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA== -"@types/estree@0.0.39": - version "0.0.39" - resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz" - integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== - "@types/estree@^0.0.50": version "0.0.50" resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz" integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw== +"@types/fs-extra@^8.0.1": + version "8.1.2" + resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-8.1.2.tgz#7125cc2e4bdd9bd2fc83005ffdb1d0ba00cca61f" + integrity sha512-SvSrYXfWSc7R4eqnOzbQF4TZmfpNSM9FrSWLU3EUnWBuyZqNBOrv1B1JA3byUDPUl9z4Ab3jeZG2eDdySlgNMg== + dependencies: + "@types/node" "*" + "@types/fs-extra@^9.0.1": version "9.0.13" resolved "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz" @@ -2410,6 +2414,11 @@ resolved "https://registry.npmjs.org/@types/node/-/node-17.0.38.tgz" integrity sha512-5jY9RhV7c0Z4Jy09G+NIDTsCZ5G0L5n+Z+p+Y7t5VJHM30bgwzSjVtlcBxqAj+6L/swIlvtOSzr8rBk/aNyV2g== +"@types/node@^18.11.9": + version "18.17.6" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.17.6.tgz#0296e9a30b22d2a8fcaa48d3c45afe51474ca55b" + integrity sha512-fGmT/P7z7ecA6bv/ia5DlaWCH4YeZvAQMNpUhrJjtAhOhZfoxS1VLUgU2pdk63efSjQaOJWdXMuAJsws+8I6dg== + "@types/normalize-package-data@^2.4.0": version "2.4.1" resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" @@ -2425,6 +2434,13 @@ resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz" integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== +"@types/react-dom@^18.0.8": + version "18.2.7" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.7.tgz#67222a08c0a6ae0a0da33c3532348277c70abb63" + integrity sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA== + dependencies: + "@types/react" "*" + "@types/react-redux@^7.1.20": version "7.1.24" resolved "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.24.tgz" @@ -2444,6 +2460,15 @@ "@types/scheduler" "*" csstype "^3.0.2" +"@types/react@^18.0.25": + version "18.2.20" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.20.tgz#1605557a83df5c8a2cc4eeb743b3dfc0eb6aaeb2" + integrity sha512-WKNtmsLWJM/3D5mG4U84cysVY31ivmyw85dE84fOCk5Hx78wezB/XEjVPWl2JTZ5FkEeaTJf+VgUAUn3PE7Isw== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + "@types/resolve@1.20.2": version "1.20.2" resolved "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz" @@ -3432,7 +3457,7 @@ colord@^2.9.1, colord@^2.9.2, colord@^2.9.3: resolved "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz" integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw== -colorette@^1.4.0: +colorette@^1.1.0, colorette@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz" integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g== @@ -4097,6 +4122,14 @@ domutils@^3.0.1: domelementtype "^2.3.0" domhandler "^5.0.1" +dot-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" + integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + dotenv@^10.0.0: version "10.0.0" resolved "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz" @@ -4560,11 +4593,6 @@ estree-walker@^0.6.1: resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz" integrity sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w== -estree-walker@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz" - integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg== - estree-walker@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz" @@ -4822,6 +4850,15 @@ fs-extra@^11.0.0: jsonfile "^6.0.1" universalify "^2.0.0" +fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs-extra@^9.0.0: version "9.1.0" resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz" @@ -4945,6 +4982,11 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + glob@7.1.7: version "7.1.7" resolved "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz" @@ -5020,6 +5062,20 @@ globalyzer@0.1.0: resolved "https://registry.yarnpkg.com/globalyzer/-/globalyzer-0.1.0.tgz#cb76da79555669a1519d5a8edf093afaa0bf1465" integrity sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q== +globby@10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/globby/-/globby-10.0.1.tgz#4782c34cb75dd683351335c5829cc3420e606b22" + integrity sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A== + dependencies: + "@types/glob" "^7.1.1" + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.0.3" + glob "^7.1.3" + ignore "^5.1.1" + merge2 "^1.2.3" + slash "^3.0.0" + globby@^10.0.1: version "10.0.2" resolved "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz" @@ -5532,6 +5588,11 @@ is-plain-obj@^2.0.0: resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz" integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== +is-plain-object@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-3.0.1.tgz#662d92d24c0aa4302407b0d45d21f2251c85f85b" + integrity sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g== + is-plain-object@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" @@ -5752,6 +5813,13 @@ jsonc-parser@^3.2.0: resolved "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz" integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w== +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== + optionalDependencies: + graceful-fs "^4.1.6" + jsonfile@^6.0.1: version "6.1.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" @@ -6041,6 +6109,13 @@ loud-rejection@^2.2.0: currently-unhandled "^0.4.1" signal-exit "^3.0.2" +lower-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" + integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== + dependencies: + tslib "^2.0.3" + lru-cache@^10.0.0: version "10.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.0.0.tgz#b9e2a6a72a129d81ab317202d93c7691df727e61" @@ -6074,12 +6149,12 @@ magic-string@^0.27.0: dependencies: "@jridgewell/sourcemap-codec" "^1.4.13" -magic-string@^0.30.0: - version "0.30.0" - resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.30.0.tgz" - integrity sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ== +magic-string@^0.30.2: + version "0.30.2" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.2.tgz#dcf04aad3d0d1314bc743d076c50feb29b3c7aca" + integrity sha512-lNZdu7pewtq/ZvWUp9Wpf/x7WzMTsR26TWV03BRZrXFsv+BI6dy8RAiKgm1uM/kyR0rCfUcqvOlXKG66KhIGug== dependencies: - "@jridgewell/sourcemap-codec" "^1.4.13" + "@jridgewell/sourcemap-codec" "^1.4.15" make-dir@^3.0.0: version "3.1.0" @@ -6380,33 +6455,43 @@ next-basics@^0.36.0: jsonwebtoken "^9.0.0" pure-rand "^6.0.2" -next@13.3.1: - version "13.3.1" - resolved "https://registry.yarnpkg.com/next/-/next-13.3.1.tgz#17625f7423db2e059d71b41bd9031756cf2b33bc" - integrity sha512-eByWRxPzKHs2oQz1yE41LX35umhz86ZSZ+mYyXBqn2IBi2hyUqxBA88avywdr4uyH+hCJczegGsDGWbzQA5Rqw== +next@13.4.19: + version "13.4.19" + resolved "https://registry.yarnpkg.com/next/-/next-13.4.19.tgz#2326e02aeedee2c693d4f37b90e4f0ed6882b35f" + integrity sha512-HuPSzzAbJ1T4BD8e0bs6B9C1kWQ6gv8ykZoRWs5AQoiIuqbGHHdQO7Ljuvg05Q0Z24E2ABozHe6FxDvI6HfyAw== dependencies: - "@next/env" "13.3.1" - "@swc/helpers" "0.5.0" + "@next/env" "13.4.19" + "@swc/helpers" "0.5.1" busboy "1.6.0" caniuse-lite "^1.0.30001406" postcss "8.4.14" styled-jsx "5.1.1" + watchpack "2.4.0" + zod "3.21.4" optionalDependencies: - "@next/swc-darwin-arm64" "13.3.1" - "@next/swc-darwin-x64" "13.3.1" - "@next/swc-linux-arm64-gnu" "13.3.1" - "@next/swc-linux-arm64-musl" "13.3.1" - "@next/swc-linux-x64-gnu" "13.3.1" - "@next/swc-linux-x64-musl" "13.3.1" - "@next/swc-win32-arm64-msvc" "13.3.1" - "@next/swc-win32-ia32-msvc" "13.3.1" - "@next/swc-win32-x64-msvc" "13.3.1" + "@next/swc-darwin-arm64" "13.4.19" + "@next/swc-darwin-x64" "13.4.19" + "@next/swc-linux-arm64-gnu" "13.4.19" + "@next/swc-linux-arm64-musl" "13.4.19" + "@next/swc-linux-x64-gnu" "13.4.19" + "@next/swc-linux-x64-musl" "13.4.19" + "@next/swc-win32-arm64-msvc" "13.4.19" + "@next/swc-win32-ia32-msvc" "13.4.19" + "@next/swc-win32-x64-msvc" "13.4.19" nice-try@^1.0.4: version "1.0.5" resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== +no-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" + integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== + dependencies: + lower-case "^2.0.2" + tslib "^2.0.3" + node-abi@^3.3.0: version "3.45.0" resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.45.0.tgz#f568f163a3bfca5aacfce1fbeee1fa2cc98441f5" @@ -6788,7 +6873,7 @@ picocolors@^1.0.0: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.3.1: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -8023,6 +8108,17 @@ rimraf@^3.0.0, rimraf@^3.0.2: dependencies: glob "^7.1.3" +rollup-plugin-copy@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/rollup-plugin-copy/-/rollup-plugin-copy-3.4.0.tgz#f1228a3ffb66ffad8606e2f3fb7ff23141ed3286" + integrity sha512-rGUmYYsYsceRJRqLVlE9FivJMxJ7X6jDlP79fmFkL8sJs7VVMSVyA2yfyL+PGyO/vJs4A87hwhgVfz61njI+uQ== + dependencies: + "@types/fs-extra" "^8.0.1" + colorette "^1.1.0" + fs-extra "^8.1.0" + globby "10.0.1" + is-plain-object "^3.0.0" + rollup-plugin-delete@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/rollup-plugin-delete/-/rollup-plugin-delete-2.0.0.tgz" @@ -8030,14 +8126,14 @@ rollup-plugin-delete@^2.0.0: dependencies: del "^5.1.0" -rollup-plugin-dts@^5.3.0: - version "5.3.0" - resolved "https://registry.npmjs.org/rollup-plugin-dts/-/rollup-plugin-dts-5.3.0.tgz" - integrity sha512-8FXp0ZkyZj1iU5klkIJYLjIq/YZSwBoERu33QBDxm/1yw5UU4txrEtcmMkrq+ZiKu3Q4qvPCNqc3ovX6rjqzbQ== +rollup-plugin-dts@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/rollup-plugin-dts/-/rollup-plugin-dts-5.3.1.tgz#c2841269a3a5cb986b7791b0328e6a178eba108f" + integrity sha512-gusMi+Z4gY/JaEQeXnB0RUdU82h1kF0WYzCWgVmV4p3hWXqelaKuCvcJawfeg+EKn2T1Ie+YWF2OiN1/L8bTVg== dependencies: - magic-string "^0.30.0" + magic-string "^0.30.2" optionalDependencies: - "@babel/code-frame" "^7.18.6" + "@babel/code-frame" "^7.22.5" rollup-plugin-esbuild@^5.0.0: version "5.0.0" @@ -8050,10 +8146,10 @@ rollup-plugin-esbuild@^5.0.0: joycon "^3.1.1" jsonc-parser "^3.2.0" -rollup-plugin-node-externals@^5.1.2: - version "5.1.3" - resolved "https://registry.npmjs.org/rollup-plugin-node-externals/-/rollup-plugin-node-externals-5.1.3.tgz" - integrity sha512-Q3VMjsn39r0/mjKrX++rFlC7kwL7YZdScdyU7BEo+PrEremal3mnol/1X+wQUU++7NeqC1ZNAeRYnHGtsTu9GQ== +rollup-plugin-node-externals@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/rollup-plugin-node-externals/-/rollup-plugin-node-externals-6.1.1.tgz#dff1a85073fe3c0b2c423b280259fe80392026a8" + integrity sha512-127OFMkpH5rBVlRHRBDUMk1m1sGuzbGy7so5aj/IkpUb2r3+wOWjR/erUzd2ChEQWPsxsyQG6xpYYvPBAdcBRA== rollup-plugin-postcss@^4.0.2: version "4.0.2" @@ -8091,10 +8187,10 @@ rollup-pluginutils@^2.8.2: dependencies: estree-walker "^0.6.1" -rollup@^2.70.1: - version "2.79.1" - resolved "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz" - integrity sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw== +rollup@^3.28.0: + version "3.28.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.28.0.tgz#a3c70004b01934760c0cb8df717c7a1d932389a2" + integrity sha512-d7zhvo1OUY2SXSM6pfNjgD5+d0Nz87CUp4mt8l/GgVP3oBsPwzNvSzyu1me6BSG9JIgWNTVcafIXBIyM8yQ3yw== optionalDependencies: fsevents "~2.3.2" @@ -8339,6 +8435,14 @@ slice-ansi@^4.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" +snake-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c" + integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + sort-keys@^4.0.0: version "4.2.0" resolved "https://registry.npmjs.org/sort-keys/-/sort-keys-4.2.0.tgz" @@ -8940,6 +9044,11 @@ tslib@^2.0.1, tslib@^2.1.0: resolved "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz" integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== +tslib@^2.0.3: + version "2.6.2" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" + integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== + tslib@^2.4.0: version "2.5.0" resolved "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz" @@ -9052,11 +9161,16 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" -typescript@^4.0, typescript@^4.5, typescript@^4.9.5: +typescript@^4.0, typescript@^4.5: version "4.9.5" resolved "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz" integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== +typescript@^5.1.6: + version "5.1.6" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274" + integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA== + ufo@^1.0.0, ufo@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.1.2.tgz#d0d9e0fa09dece0c31ffd57bd363f030a35cfe76" @@ -9128,6 +9242,11 @@ unicode-property-aliases-ecmascript@^2.0.0: resolved "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz" integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + universalify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" @@ -9228,6 +9347,14 @@ vue@^3.2.23: "@vue/server-renderer" "3.2.36" "@vue/shared" "3.2.36" +watchpack@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" + integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== + dependencies: + glob-to-regexp "^0.4.1" + graceful-fs "^4.1.2" + web-streams-polyfill@^3.0.3: version "3.2.1" resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6" @@ -9394,6 +9521,11 @@ yup@^0.32.11: property-expr "^2.0.4" toposort "^2.0.2" +zod@3.21.4: + version "3.21.4" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.21.4.tgz#10882231d992519f0a10b5dd58a38c9dabbb64db" + integrity sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw== + zustand@^4.3.8: version "4.3.9" resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.3.9.tgz#a7d4332bbd75dfd25c6848180b3df1407217f2ad"