diff --git a/package.json b/package.json index 2e93d58c..bbf25099 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "@react-spring/web": "^9.7.3", "@svgr/cli": "^8.1.0", "@tanstack/react-query": "^5.28.6", - "@umami/react-zen": "^0.117.0", + "@umami/react-zen": "^0.118.0", "@umami/redis-client": "^0.27.0", "bcryptjs": "^2.4.3", "chalk": "^4.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fa4add0b..d359cb9d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -42,8 +42,8 @@ importers: specifier: ^5.28.6 version: 5.76.1(react@19.1.0) '@umami/react-zen': - specifier: ^0.117.0 - version: 0.117.0(@babel/core@7.27.1)(@types/react@19.1.4)(immer@9.0.21)(use-sync-external-store@1.5.0(react@19.1.0)) + specifier: ^0.118.0 + version: 0.118.0(@babel/core@7.27.1)(@types/react@19.1.4)(immer@9.0.21)(use-sync-external-store@1.5.0(react@19.1.0)) '@umami/redis-client': specifier: ^0.27.0 version: 0.27.0 @@ -3035,8 +3035,8 @@ packages: resolution: {integrity: sha512-ar0tjQfObzhSaW3C3QNmTc5ofj0hDoNQ5XWrCy6zDyabdr0TWhCkClp+rywGNj/odAFBVzzJrK4tEq5M4Hmu4w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@umami/react-zen@0.117.0': - resolution: {integrity: sha512-vo1i25cBpMsAWNHJ4RPFDJzlaH93NXwx8VotmnoAWgP39Yy+fdUwmi+dDXNBOKvWzoHO9BFf0nIYiT16klnR6g==} + '@umami/react-zen@0.118.0': + resolution: {integrity: sha512-XnaR499ZysBXph+GFEmiHzXOKYWveHMEXMgeMKZqyaXAEU76UTfVJJifgC2MEWMfOxZAyT308EFJh0s4hc/3eA==} '@umami/redis-client@0.27.0': resolution: {integrity: sha512-SbHTpxhgeZyTBUSp2zdZM+XUtpsaSL4Tad8QXIEhEtjWhvvfoornyT5kLuyYCVtzSAT4daALeGmOO1z6EE1KcA==} @@ -10860,7 +10860,7 @@ snapshots: '@typescript-eslint/types': 8.32.1 eslint-visitor-keys: 4.2.0 - '@umami/react-zen@0.117.0(@babel/core@7.27.1)(@types/react@19.1.4)(immer@9.0.21)(use-sync-external-store@1.5.0(react@19.1.0))': + '@umami/react-zen@0.118.0(@babel/core@7.27.1)(@types/react@19.1.4)(immer@9.0.21)(use-sync-external-store@1.5.0(react@19.1.0))': dependencies: '@fontsource/jetbrains-mono': 5.2.5 '@internationalized/date': 3.8.1 diff --git a/src/app/(main)/reports/retention/RetentionParameters.tsx b/src/app/(main)/reports/retention/RetentionParameters.tsx deleted file mode 100644 index e49c8529..00000000 --- a/src/app/(main)/reports/retention/RetentionParameters.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { useMessages, useReport } from '@/components/hooks'; -import { Form, FormButtons, FormSubmitButton } from '@umami/react-zen'; -import { BaseParameters } from '../[reportId]/BaseParameters'; - -export function RetentionParameters() { - const { report, runReport, isRunning } = useReport(); - const { formatMessage, labels } = useMessages(); - - const { id, parameters } = report || {}; - const { websiteId, dateRange } = parameters || {}; - const queryDisabled = !websiteId || !dateRange; - - const handleSubmit = (data: any, e: any) => { - e.stopPropagation(); - e.preventDefault(); - - if (!queryDisabled) { - runReport(data); - } - }; - - return ( -
- - - - - {formatMessage(labels.runQuery)} - - - - ); -} diff --git a/src/app/(main)/reports/retention/RetentionReport.module.css b/src/app/(main)/reports/retention/RetentionReport.module.css deleted file mode 100644 index aed66b74..00000000 --- a/src/app/(main)/reports/retention/RetentionReport.module.css +++ /dev/null @@ -1,10 +0,0 @@ -.filters { - display: flex; - flex-direction: column; - justify-content: space-between; - border: 1px solid var(--base400); - border-radius: var(--border-radius); - line-height: 32px; - padding: 10px; - overflow: hidden; -} diff --git a/src/app/(main)/reports/retention/RetentionReport.tsx b/src/app/(main)/reports/retention/RetentionReport.tsx deleted file mode 100644 index 1025ff5e..00000000 --- a/src/app/(main)/reports/retention/RetentionReport.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { RetentionTable } from './RetentionTable'; -import { RetentionParameters } from './RetentionParameters'; -import { Report } from '../[reportId]/Report'; -import { ReportHeader } from '../[reportId]/ReportHeader'; -import { ReportMenu } from '../[reportId]/ReportMenu'; -import { ReportBody } from '../[reportId]/ReportBody'; -import { Icons } from '@/components/icons'; -import { REPORT_TYPES } from '@/lib/constants'; -import { parseDateRange } from '@/lib/date'; -import { endOfMonth, startOfMonth } from 'date-fns'; - -const defaultParameters = { - type: REPORT_TYPES.retention, - parameters: { - dateRange: parseDateRange( - `range:${startOfMonth(new Date()).getTime()}:${endOfMonth(new Date()).getTime()}`, - ), - }, -}; - -export function RetentionReport({ reportId }: { reportId?: string }) { - return ( - - } /> - - - - - - - - ); -} diff --git a/src/app/(main)/reports/retention/RetentionReportPage.tsx b/src/app/(main)/reports/retention/RetentionReportPage.tsx deleted file mode 100644 index a12c690c..00000000 --- a/src/app/(main)/reports/retention/RetentionReportPage.tsx +++ /dev/null @@ -1,11 +0,0 @@ -'use client'; -import { Metadata } from 'next'; -import { RetentionReport } from './RetentionReport'; - -export function RetentionReportPage() { - return ; -} - -export const metadata: Metadata = { - title: 'Retention Report', -}; diff --git a/src/app/(main)/reports/retention/RetentionTable.module.css b/src/app/(main)/reports/retention/RetentionTable.module.css deleted file mode 100644 index bfe3ac1c..00000000 --- a/src/app/(main)/reports/retention/RetentionTable.module.css +++ /dev/null @@ -1,52 +0,0 @@ -.table { - display: flex; - flex-direction: column; -} - -.header { - font-weight: 700; -} - -.row { - display: flex; - flex-direction: row; - gap: 1px; - margin-bottom: 1px; -} - -.cell { - display: flex; - align-items: center; - justify-content: center; - width: 60px; - height: 60px; - background: var(--blue200); - border-radius: var(--border-radius); -} - -.date { - display: flex; - align-items: center; - min-width: 160px; -} - -.visitors { - display: flex; - align-items: center; - min-width: 80px; -} - -.day { - display: flex; - align-items: center; - justify-content: center; - width: 60px; - height: 60px; - text-align: center; - font-size: var(--font-size-sm); - font-weight: 400; -} - -.empty { - background: var(--blue100); -} diff --git a/src/app/(main)/reports/retention/RetentionTable.tsx b/src/app/(main)/reports/retention/RetentionTable.tsx deleted file mode 100644 index 78ee3fb4..00000000 --- a/src/app/(main)/reports/retention/RetentionTable.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import classNames from 'classnames'; -import { EmptyPlaceholder } from '@/components/common/EmptyPlaceholder'; -import { useMessages, useLocale, useReport } from '@/components/hooks'; -import { formatDate } from '@/lib/date'; -import styles from './RetentionTable.module.css'; - -const DAYS = [1, 2, 3, 4, 5, 6, 7, 14, 21, 28]; - -export function RetentionTable({ days = DAYS }) { - const { formatMessage, labels } = useMessages(); - const { locale } = useLocale(); - const { report } = useReport(); - const { data } = report || {}; - - if (!data) { - return ; - } - - const rows = data.reduce((arr: any[], row: { date: any; visitors: any; day: any }) => { - const { date, visitors, day } = row; - if (day === 0) { - return arr.concat({ - date, - visitors, - records: days - .reduce((arr, day) => { - arr[day] = data.find(x => x.date === date && x.day === day); - return arr; - }, []) - .filter(n => n), - }); - } - return arr; - }, []); - - const totalDays = rows.length; - - return ( - <> -
-
-
{formatMessage(labels.date)}
-
{formatMessage(labels.visitors)}
- {days.map(n => ( -
- {formatMessage(labels.day)} {n} -
- ))} -
- {rows.map(({ date, visitors, records }, rowIndex) => { - return ( -
-
{formatDate(date, 'PP', locale)}
-
{visitors}
- {days.map(day => { - if (totalDays - rowIndex < day) { - return null; - } - const percentage = records.filter(a => a.day === day)[0]?.percentage; - return ( -
- {percentage ? `${Number(percentage).toFixed(2)}%` : ''} -
- ); - })} -
- ); - })} -
- - ); -} diff --git a/src/app/(main)/reports/retention/page.tsx b/src/app/(main)/reports/retention/page.tsx deleted file mode 100644 index 98560c52..00000000 --- a/src/app/(main)/reports/retention/page.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { Metadata } from 'next'; -import { RetentionReportPage } from './RetentionReportPage'; - -export default function () { - return ; -} - -export const metadata: Metadata = { - title: 'Retention Report', -}; diff --git a/src/app/(main)/reports/revenue/RevenueParameters.tsx b/src/app/(main)/reports/revenue/RevenueParameters.tsx deleted file mode 100644 index 9bbd0044..00000000 --- a/src/app/(main)/reports/revenue/RevenueParameters.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { useMessages, useReport } from '@/components/hooks'; -import { useRevenueValuesQuery } from '@/components/hooks/queries/useRevenueValuesQuery'; -import { Select, Form, FormButtons, FormField, ListItem, FormSubmitButton } from '@umami/react-zen'; -import { BaseParameters } from '../[reportId]/BaseParameters'; - -export function RevenueParameters() { - const { report, runReport, isRunning } = useReport(); - const { formatMessage, labels } = useMessages(); - const { id, parameters } = report || {}; - const { websiteId, dateRange } = parameters || {}; - const queryEnabled = websiteId && dateRange; - const { data: values = [] } = useRevenueValuesQuery( - websiteId, - dateRange?.startDate, - dateRange?.endDate, - ); - - const handleSubmit = (data: any, e: any) => { - e.stopPropagation(); - e.preventDefault(); - - runReport(data); - }; - - return ( -
- - - - - - - - {formatMessage(labels.runQuery)} - - - - ); -} diff --git a/src/app/(main)/reports/revenue/RevenueReport.tsx b/src/app/(main)/reports/revenue/RevenueReport.tsx deleted file mode 100644 index a692c711..00000000 --- a/src/app/(main)/reports/revenue/RevenueReport.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { Icons } from '@/components/icons'; -import { REPORT_TYPES } from '@/lib/constants'; -import { Report } from '../[reportId]/Report'; -import { ReportBody } from '../[reportId]/ReportBody'; -import { ReportHeader } from '../[reportId]/ReportHeader'; -import { ReportMenu } from '../[reportId]/ReportMenu'; -import { RevenueParameters } from './RevenueParameters'; -import { RevenueView } from './RevenueView'; - -const defaultParameters = { - type: REPORT_TYPES.revenue, - parameters: {}, -}; - -export function RevenueReport({ reportId }: { reportId?: string }) { - return ( - - } /> - - - - - - - - ); -} diff --git a/src/app/(main)/reports/revenue/RevenueReportPage.tsx b/src/app/(main)/reports/revenue/RevenueReportPage.tsx deleted file mode 100644 index 990c62c9..00000000 --- a/src/app/(main)/reports/revenue/RevenueReportPage.tsx +++ /dev/null @@ -1,6 +0,0 @@ -'use client'; -import { RevenueReport } from './RevenueReport'; - -export function RevenueReportPage() { - return ; -} diff --git a/src/app/(main)/reports/revenue/RevenueTable.tsx b/src/app/(main)/reports/revenue/RevenueTable.tsx deleted file mode 100644 index cc0c8013..00000000 --- a/src/app/(main)/reports/revenue/RevenueTable.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { EmptyPlaceholder } from '@/components/common/EmptyPlaceholder'; -import { useMessages, useReport } from '@/components/hooks'; -import { DataColumn, DataTable } from '@umami/react-zen'; -import { formatLongCurrency } from '@/lib/format'; - -export function RevenueTable() { - const { report } = useReport(); - const { formatMessage, labels } = useMessages(); - const { data } = report || {}; - - if (!data) { - return ; - } - - return ( - - - {(row: any) => row.currency} - - - {(row: any) => formatLongCurrency(row.sum, row.currency)} - - - {(row: any) => formatLongCurrency(row.count ? row.sum / row.count : 0, row.currency)} - - - {(row: any) => row.count} - - - {(row: any) => row.unique_count} - - - ); -} diff --git a/src/app/(main)/reports/revenue/RevenueView.module.css b/src/app/(main)/reports/revenue/RevenueView.module.css deleted file mode 100644 index 9b35260e..00000000 --- a/src/app/(main)/reports/revenue/RevenueView.module.css +++ /dev/null @@ -1,11 +0,0 @@ -.container { - display: grid; - gap: 20px; - margin-bottom: 40px; -} - -.row { - display: flex; - align-items: center; - gap: 10px; -} diff --git a/src/app/(main)/reports/revenue/RevenueView.tsx b/src/app/(main)/reports/revenue/RevenueView.tsx deleted file mode 100644 index e3e60c76..00000000 --- a/src/app/(main)/reports/revenue/RevenueView.tsx +++ /dev/null @@ -1,153 +0,0 @@ -import classNames from 'classnames'; -import { colord } from 'colord'; -import { BarChart } from '@/components/charts/BarChart'; -import { PieChart } from '@/components/charts/PieChart'; -import { TypeIcon } from '@/components/common/TypeIcon'; -import { useCountryNames, useLocale, useMessages, useReport } from '@/components/hooks'; -import { GridRow } from '@/components/common/GridRow'; -import { ListTable } from '@/components/metrics/ListTable'; -import { MetricCard } from '@/components/metrics/MetricCard'; -import { MetricsBar } from '@/components/metrics/MetricsBar'; -import { renderDateLabels } from '@/lib/charts'; -import { CHART_COLORS } from '@/lib/constants'; -import { formatLongCurrency, formatLongNumber } from '@/lib/format'; -import { useCallback, useMemo } from 'react'; -import { RevenueTable } from './RevenueTable'; -import styles from './RevenueView.module.css'; - -export interface RevenueViewProps { - isLoading?: boolean; -} - -export function RevenueView({ isLoading }: RevenueViewProps) { - const { formatMessage, labels } = useMessages(); - const { locale } = useLocale(); - const { countryNames } = useCountryNames(locale); - const { report } = useReport(); - const { - data, - parameters: { dateRange, currency }, - } = report || {}; - const showTable = data?.table.length > 1; - - const renderCountryName = useCallback( - ({ x: code }) => ( - - - {countryNames[code]} - - ), - [countryNames, locale], - ); - - const chartData = useMemo(() => { - if (!data) return []; - - const map = (data.chart as any[]).reduce((obj, { x, t, y }) => { - if (!obj[x]) { - obj[x] = []; - } - - obj[x].push({ x: t, y }); - - return obj; - }, {}); - - return { - datasets: Object.keys(map).map((key, index) => { - const color = colord(CHART_COLORS[index % CHART_COLORS.length]); - return { - label: key, - data: map[key], - lineTension: 0, - backgroundColor: color.alpha(0.6).toRgbString(), - borderColor: color.alpha(0.7).toRgbString(), - borderWidth: 1, - }; - }), - }; - }, [data]); - - const countryData = useMemo(() => { - if (!data) return []; - - const labels = data.country.map(({ name }) => name); - const datasets = [ - { - data: data.country.map(({ value }) => value), - backgroundColor: CHART_COLORS, - borderWidth: 0, - }, - ]; - - return { labels, datasets }; - }, [data]); - - const metricData = useMemo(() => { - if (!data) return []; - - const { sum, count, unique_count } = data.total; - - return [ - { - value: sum, - label: formatMessage(labels.total), - formatValue: n => formatLongCurrency(n, currency), - }, - { - value: count ? sum / count : 0, - label: formatMessage(labels.average), - formatValue: n => formatLongCurrency(n, currency), - }, - { - value: count, - label: formatMessage(labels.transactions), - formatValue: formatLongNumber, - }, - { - value: unique_count, - label: formatMessage(labels.uniqueCustomers), - formatValue: formatLongNumber, - }, - ] as any; - }, [data, locale]); - - return ( - <> -
- - {metricData?.map(({ label, value, formatValue }) => { - return ; - })} - - {data && ( - <> - - - ({ - x: name, - y: Number(value), - z: (value / data?.total.sum) * 100, - }))} - renderLabel={renderCountryName} - /> - - - - )} - {showTable && } -
- - ); -} diff --git a/src/app/(main)/reports/revenue/page.tsx b/src/app/(main)/reports/revenue/page.tsx deleted file mode 100644 index 40281259..00000000 --- a/src/app/(main)/reports/revenue/page.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { RevenueReportPage } from './RevenueReportPage'; -import { Metadata } from 'next'; - -export default function () { - return ; -} - -export const metadata: Metadata = { - title: 'Revenue Report', -}; diff --git a/src/app/(main)/reports/utm/UTMParameters.tsx b/src/app/(main)/reports/utm/UTMParameters.tsx deleted file mode 100644 index 759f77f5..00000000 --- a/src/app/(main)/reports/utm/UTMParameters.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { useMessages, useReport } from '@/components/hooks'; -import { Form, FormButtons, FormSubmitButton } from '@umami/react-zen'; -import { BaseParameters } from '../[reportId]/BaseParameters'; - -export function UTMParameters() { - const { report, runReport, isRunning } = useReport(); - const { formatMessage, labels } = useMessages(); - - const { id, parameters } = report || {}; - const { websiteId, dateRange } = parameters || {}; - const queryDisabled = !websiteId || !dateRange; - - const handleSubmit = (data: any, e: any) => { - e.stopPropagation(); - e.preventDefault(); - - if (!queryDisabled) { - runReport(data); - } - }; - - return ( -
- - - - {formatMessage(labels.runQuery)} - - - - ); -} diff --git a/src/app/(main)/reports/utm/UTMReport.tsx b/src/app/(main)/reports/utm/UTMReport.tsx deleted file mode 100644 index d36e354f..00000000 --- a/src/app/(main)/reports/utm/UTMReport.tsx +++ /dev/null @@ -1,28 +0,0 @@ -'use client'; -import { Report } from '../[reportId]/Report'; -import { ReportHeader } from '../[reportId]/ReportHeader'; -import { ReportMenu } from '../[reportId]/ReportMenu'; -import { ReportBody } from '../[reportId]/ReportBody'; -import { UTMParameters } from './UTMParameters'; -import { UTMView } from './UTMView'; -import { Icons } from '@/components/icons'; -import { REPORT_TYPES } from '@/lib/constants'; - -const defaultParameters = { - type: REPORT_TYPES.utm, - parameters: {}, -}; - -export function UTMReport({ reportId }: { reportId?: string }) { - return ( - - } /> - - - - - - - - ); -} diff --git a/src/app/(main)/reports/utm/UTMReportPage.tsx b/src/app/(main)/reports/utm/UTMReportPage.tsx deleted file mode 100644 index 92db240f..00000000 --- a/src/app/(main)/reports/utm/UTMReportPage.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { UTMReport } from './UTMReport'; - -export function UTMReportPage() { - return ; -} diff --git a/src/app/(main)/reports/utm/UTMView.module.css b/src/app/(main)/reports/utm/UTMView.module.css deleted file mode 100644 index fa7cc0b4..00000000 --- a/src/app/(main)/reports/utm/UTMView.module.css +++ /dev/null @@ -1,14 +0,0 @@ -.title { - font-size: 24px; - line-height: 36px; - font-weight: 700; -} - -.row { - display: grid; - grid-template-columns: 50% 50%; - gap: 20px; - border-bottom: 1px solid var(--base300); - padding-bottom: 30px; - margin-bottom: 30px; -} diff --git a/src/app/(main)/reports/utm/UTMView.tsx b/src/app/(main)/reports/utm/UTMView.tsx deleted file mode 100644 index fea15fd8..00000000 --- a/src/app/(main)/reports/utm/UTMView.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import { firstBy } from 'thenby'; -import { CHART_COLORS, UTM_PARAMS } from '@/lib/constants'; -import { useReport } from '@/components/hooks'; -import { PieChart } from '@/components/charts/PieChart'; -import { ListTable } from '@/components/metrics/ListTable'; -import styles from './UTMView.module.css'; -import { useMessages } from '@/components/hooks'; - -function toArray(data: { [key: string]: number } = {}) { - return Object.keys(data) - .map(key => { - return { name: key, value: data[key] }; - }) - .sort(firstBy('value', -1)); -} - -export function UTMView() { - const { formatMessage, labels } = useMessages(); - const { report } = useReport(); - const { data } = report || {}; - - if (!data) { - return null; - } - - return ( -
- {UTM_PARAMS.map(param => { - const items = toArray(data[param]); - const chartData = { - labels: items.map(({ name }) => name), - datasets: [ - { - data: items.map(({ value }) => value), - backgroundColor: CHART_COLORS, - borderWidth: 0, - }, - ], - }; - const total = items.reduce((sum, { value }) => { - return +sum + +value; - }, 0); - - return ( -
-
-
{param.replace(/^utm_/, '')}
- ({ - x: name, - y: value, - z: (value / total) * 100, - }))} - /> -
-
- -
-
- ); - })} -
- ); -} diff --git a/src/app/(main)/reports/utm/page.tsx b/src/app/(main)/reports/utm/page.tsx deleted file mode 100644 index 110e72c2..00000000 --- a/src/app/(main)/reports/utm/page.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { Metadata } from 'next'; -import { UTMReportPage } from './UTMReportPage'; - -export default function () { - return ; -} - -export const metadata: Metadata = { - title: 'Goals Report', -}; diff --git a/src/app/(main)/websites/[websiteId]/WebsiteDetailsPage.tsx b/src/app/(main)/websites/[websiteId]/WebsiteDetailsPage.tsx index ac634c7b..382041d1 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteDetailsPage.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteDetailsPage.tsx @@ -16,7 +16,7 @@ export function WebsiteDetailsPage({ websiteId }: { websiteId: string }) { return ( - + diff --git a/src/app/(main)/websites/[websiteId]/WebsiteNav.tsx b/src/app/(main)/websites/[websiteId]/WebsiteNav.tsx index 084cac9d..aff7ea79 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteNav.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteNav.tsx @@ -80,12 +80,6 @@ export function WebsiteNav({ websiteId }: { websiteId: string }) { icon: , path: '/attribution', }, - { - id: 'reports', - label: formatMessage(labels.reports), - icon: , - path: '/reports', - }, ]; const selected = links.find(({ path }) => path && pathname.endsWith(path))?.id || 'overview'; diff --git a/src/app/(main)/websites/[websiteId]/goals/GoalAddButton.tsx b/src/app/(main)/websites/[websiteId]/goals/GoalAddButton.tsx new file mode 100644 index 00000000..b1b672ff --- /dev/null +++ b/src/app/(main)/websites/[websiteId]/goals/GoalAddButton.tsx @@ -0,0 +1,24 @@ +import { Button, MenuTrigger, Dialog, Icon, Text, Modal } from '@umami/react-zen'; +import { useMessages } from '@/components/hooks'; +import { GoalAddForm } from './GoalAddForm'; +import { Icons } from '@/components/icons'; + +export function GoalAddButton({ websiteId }: { websiteId: string }) { + const { formatMessage, labels } = useMessages(); + + return ( + + + + + {({ close }) => } + + + + ); +} diff --git a/src/app/(main)/websites/[websiteId]/goals/GoalAddForm.tsx b/src/app/(main)/websites/[websiteId]/goals/GoalAddForm.tsx new file mode 100644 index 00000000..54d1b942 --- /dev/null +++ b/src/app/(main)/websites/[websiteId]/goals/GoalAddForm.tsx @@ -0,0 +1,64 @@ +import { + Form, + FormField, + TextField, + Select, + FormButtons, + FormSubmitButton, + Button, +} from '@umami/react-zen'; +import { useApi, useMessages } from '@/components/hooks'; + +export function GoalAddForm({ onSave, onClose }: { onSave?: () => void; onClose?: () => void }) { + const { formatMessage, labels } = useMessages(); + const { post, useMutation } = useApi(); + const { mutate, error, isPending } = useMutation({ + mutationFn: (data: any) => post('/websites', { ...data }), + }); + + const handleSubmit = async (data: any) => { + mutate(data, { + onSuccess: async () => { + onSave?.(); + onClose?.(); + }, + }); + }; + + const items = [ + { id: 'page', label: formatMessage(labels.page) }, + { id: 'event', label: formatMessage(labels.event) }, + ]; + + return ( +
+ + + + +