mirror of
https://github.com/kremalicious/umami.git
synced 2024-12-24 18:26:20 +01:00
Funnel Table/Chart hooked up.
This commit is contained in:
parent
1130bca195
commit
07cb9f621d
@ -9,7 +9,7 @@ import useApi from 'hooks/useApi';
|
|||||||
import useDateRange from 'hooks/useDateRange';
|
import useDateRange from 'hooks/useDateRange';
|
||||||
import useMessages from 'hooks/useMessages';
|
import useMessages from 'hooks/useMessages';
|
||||||
|
|
||||||
export function DateFilter({ websiteId, value, className, onChange, isForm, alignment }) {
|
export function DateFilter({ websiteId, value, className, onChange, alignment }) {
|
||||||
const { formatMessage, labels } = useMessages();
|
const { formatMessage, labels } = useMessages();
|
||||||
const { get } = useApi();
|
const { get } = useApi();
|
||||||
const [dateRange, setDateRange] = useDateRange(websiteId);
|
const [dateRange, setDateRange] = useDateRange(websiteId);
|
||||||
@ -23,7 +23,7 @@ export function DateFilter({ websiteId, value, className, onChange, isForm, alig
|
|||||||
if (data) {
|
if (data) {
|
||||||
const websiteRange = { value, ...getDateRangeValues(new Date(data.createdAt), Date.now()) };
|
const websiteRange = { value, ...getDateRangeValues(new Date(data.createdAt), Date.now()) };
|
||||||
|
|
||||||
if (!isForm) {
|
if (!onChange) {
|
||||||
setDateRange(websiteRange);
|
setDateRange(websiteRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,15 +32,13 @@ export function DateFilter({ websiteId, value, className, onChange, isForm, alig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (value !== 'all') {
|
} else if (value !== 'all') {
|
||||||
if (!isForm) {
|
if (!onChange) {
|
||||||
setDateRange(value);
|
setDateRange(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (onChange) {
|
if (onChange) {
|
||||||
onChange(value);
|
onChange(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ export function SettingsLayout({ children }) {
|
|||||||
const items = [
|
const items = [
|
||||||
{ key: 'websites', label: formatMessage(labels.websites), url: '/settings/websites' },
|
{ key: 'websites', label: formatMessage(labels.websites), url: '/settings/websites' },
|
||||||
{ key: 'teams', label: formatMessage(labels.teams), url: '/settings/teams' },
|
{ key: 'teams', label: formatMessage(labels.teams), url: '/settings/teams' },
|
||||||
|
{ key: 'reports', label: 'Reports', url: '/settings/reports/funnel' },
|
||||||
user.isAdmin && { key: 'users', label: formatMessage(labels.users), url: '/settings/users' },
|
user.isAdmin && { key: 'users', label: formatMessage(labels.users), url: '/settings/users' },
|
||||||
{ key: 'profile', label: formatMessage(labels.profile), url: '/settings/profile' },
|
{ key: 'profile', label: formatMessage(labels.profile), url: '/settings/profile' },
|
||||||
].filter(n => n);
|
].filter(n => n);
|
||||||
|
@ -18,7 +18,9 @@ export const labels = defineMessages({
|
|||||||
admin: { id: 'label.admin', defaultMessage: 'Administrator' },
|
admin: { id: 'label.admin', defaultMessage: 'Administrator' },
|
||||||
confirm: { id: 'label.confirm', defaultMessage: 'Confirm' },
|
confirm: { id: 'label.confirm', defaultMessage: 'Confirm' },
|
||||||
details: { id: 'label.details', defaultMessage: 'Details' },
|
details: { id: 'label.details', defaultMessage: 'Details' },
|
||||||
|
website: { id: 'label.website', defaultMessage: 'Website' },
|
||||||
websites: { id: 'label.websites', defaultMessage: 'Websites' },
|
websites: { id: 'label.websites', defaultMessage: 'Websites' },
|
||||||
|
reports: { id: 'label.reports', defaultMessage: 'Reports' },
|
||||||
created: { id: 'label.created', defaultMessage: 'Created' },
|
created: { id: 'label.created', defaultMessage: 'Created' },
|
||||||
edit: { id: 'label.edit', defaultMessage: 'Edit' },
|
edit: { id: 'label.edit', defaultMessage: 'Edit' },
|
||||||
name: { id: 'label.name', defaultMessage: 'Name' },
|
name: { id: 'label.name', defaultMessage: 'Name' },
|
||||||
@ -183,6 +185,10 @@ export const messages = defineMessages({
|
|||||||
id: 'message.delete-website-warning',
|
id: 'message.delete-website-warning',
|
||||||
defaultMessage: 'All website data will be deleted.',
|
defaultMessage: 'All website data will be deleted.',
|
||||||
},
|
},
|
||||||
|
noResultsFound: {
|
||||||
|
id: 'messages.no-results-found',
|
||||||
|
defaultMessage: 'No results were found.',
|
||||||
|
},
|
||||||
noWebsitesConfigured: {
|
noWebsitesConfigured: {
|
||||||
id: 'messages.no-websites-configured',
|
id: 'messages.no-websites-configured',
|
||||||
defaultMessage: 'You do not have any websites configured.',
|
defaultMessage: 'You do not have any websites configured.',
|
||||||
|
@ -1,43 +1,40 @@
|
|||||||
import FunnelGraph from 'funnel-graph-js/dist/js/funnel-graph';
|
import FunnelGraph from 'funnel-graph-js/dist/js/funnel-graph';
|
||||||
import { useEffect, useRef } from 'react';
|
import { useEffect, useRef } from 'react';
|
||||||
|
import EmptyPlaceholder from 'components/common/EmptyPlaceholder';
|
||||||
|
import useMessages from 'hooks/useMessages';
|
||||||
|
|
||||||
export default function FunnelChart() {
|
export default function FunnelChart({ data }) {
|
||||||
|
const { formatMessage, labels, messages } = useMessages();
|
||||||
const funnel = useRef(null);
|
const funnel = useRef(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
funnel.current.innerHTML = '';
|
if (data && data.length > 0) {
|
||||||
|
funnel.current.innerHTML = '';
|
||||||
|
|
||||||
const data = {
|
const chartData = {
|
||||||
labels: ['Cv Sent', '1st Interview', '2nd Interview', '3rd Interview', 'Offer'],
|
labels: data.map(a => a.url),
|
||||||
subLabels: ['Cv Sent', '1st Interview', '2nd Interview', '3rd Interview', 'Offer'],
|
colors: ['#147af3', '#e0f2ff'],
|
||||||
colors: [
|
values: data.map(a => a.count),
|
||||||
['#FFB178', '#FF78B1', '#FF3C8E'],
|
};
|
||||||
['#FFB178', '#FF78B1', '#FF3C8E'],
|
|
||||||
['#A0BBFF', '#EC77FF'],
|
|
||||||
['#A0F9FF', '#7795FF'],
|
|
||||||
['#FFB178', '#FF78B1', '#FF3C8E'],
|
|
||||||
],
|
|
||||||
values: [[3500], [3300], [2000], [600], [330]],
|
|
||||||
};
|
|
||||||
|
|
||||||
const graph = new FunnelGraph({
|
const graph = new FunnelGraph({
|
||||||
container: '.funnel',
|
container: '.funnel',
|
||||||
gradientDirection: 'horizontal',
|
gradientDirection: 'horizontal',
|
||||||
data: data,
|
data: chartData,
|
||||||
displayPercent: true,
|
displayPercent: true,
|
||||||
direction: 'Vertical',
|
direction: 'Vertical',
|
||||||
width: 1000,
|
width: 1000,
|
||||||
height: 350,
|
height: 350,
|
||||||
subLabelValue: 'values',
|
});
|
||||||
});
|
|
||||||
|
|
||||||
graph.draw();
|
graph.draw();
|
||||||
}, []);
|
}
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<>
|
||||||
FunnelChart
|
{data?.length > 0 && <div className="funnel" ref={funnel} />}
|
||||||
<div className="funnel" ref={funnel} />
|
{data?.length === 0 && <EmptyPlaceholder message={formatMessage(messages.noResultsFound)} />}
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,8 @@
|
|||||||
import { useMutation } from '@tanstack/react-query';
|
|
||||||
import DateFilter from 'components/input/DateFilter';
|
import DateFilter from 'components/input/DateFilter';
|
||||||
import WebsiteSelect from 'components/input/WebsiteSelect';
|
import WebsiteSelect from 'components/input/WebsiteSelect';
|
||||||
import useApi from 'hooks/useApi';
|
|
||||||
import useMessages from 'hooks/useMessages';
|
import useMessages from 'hooks/useMessages';
|
||||||
import useUser from 'hooks/useUser';
|
|
||||||
import { parseDateRange } from 'lib/date';
|
import { parseDateRange } from 'lib/date';
|
||||||
import { useRouter } from 'next/router';
|
import { useState } from 'react';
|
||||||
import { useEffect, useState } from 'react';
|
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Form,
|
Form,
|
||||||
@ -17,15 +13,15 @@ import {
|
|||||||
TextField,
|
TextField,
|
||||||
} from 'react-basics';
|
} from 'react-basics';
|
||||||
import styles from './FunnelForm.module.css';
|
import styles from './FunnelForm.module.css';
|
||||||
import { getNextInternalQuery } from 'next/dist/server/request-meta';
|
|
||||||
|
|
||||||
export function FunnelForm({ onSearch }) {
|
export function FunnelForm({ onSearch }) {
|
||||||
const { formatMessage, labels, getMessage } = useMessages();
|
const { formatMessage, labels } = useMessages();
|
||||||
const [dateRange, setDateRange] = useState(null);
|
const [dateRange, setDateRange] = useState('');
|
||||||
const [startDate, setStartDate] = useState(null);
|
const [startAt, setStartAt] = useState();
|
||||||
const [endDate, setEndDate] = useState(null);
|
const [endAt, setEndAt] = useState();
|
||||||
const [urls, setUrls] = useState(['']);
|
const [urls, setUrls] = useState(['']);
|
||||||
const [websiteId, setWebsiteId] = useState('');
|
const [websiteId, setWebsiteId] = useState('');
|
||||||
|
const [window, setWindow] = useState(60);
|
||||||
|
|
||||||
const handleSubmit = async data => {
|
const handleSubmit = async data => {
|
||||||
onSearch(data);
|
onSearch(data);
|
||||||
@ -35,14 +31,16 @@ export function FunnelForm({ onSearch }) {
|
|||||||
const { startDate, endDate } = parseDateRange(value);
|
const { startDate, endDate } = parseDateRange(value);
|
||||||
|
|
||||||
setDateRange(value);
|
setDateRange(value);
|
||||||
setStartDate(startDate);
|
setStartAt(startDate.getTime());
|
||||||
setEndDate(endDate);
|
setEndAt(endDate.getTime());
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAddUrl = () => setUrls([...urls, 'meow']);
|
const handleAddUrl = () => setUrls([...urls, '']);
|
||||||
|
|
||||||
const handleRemoveUrl = i => setUrls(urls.splice(i, 1));
|
const handleRemoveUrl = i => setUrls(urls.splice(i, 1));
|
||||||
|
|
||||||
|
const handleWindowChange = value => setWindow(value.target.value);
|
||||||
|
|
||||||
const handleUrlChange = (value, i) => {
|
const handleUrlChange = (value, i) => {
|
||||||
const nextUrls = [...urls];
|
const nextUrls = [...urls];
|
||||||
|
|
||||||
@ -55,13 +53,14 @@ export function FunnelForm({ onSearch }) {
|
|||||||
<Form
|
<Form
|
||||||
values={{
|
values={{
|
||||||
websiteId,
|
websiteId,
|
||||||
startDate,
|
startAt,
|
||||||
endDate,
|
endAt,
|
||||||
urls,
|
urls,
|
||||||
|
window,
|
||||||
}}
|
}}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
>
|
>
|
||||||
<FormRow label="website">
|
<FormRow label={formatMessage(labels.website)}>
|
||||||
<WebsiteSelect websiteId={websiteId} onSelect={value => setWebsiteId(value)} />
|
<WebsiteSelect websiteId={websiteId} onSelect={value => setWebsiteId(value)} />
|
||||||
<FormInput name="websiteId" rules={{ required: formatMessage(labels.required) }}>
|
<FormInput name="websiteId" rules={{ required: formatMessage(labels.required) }}>
|
||||||
<TextField value={websiteId} className={styles.hiddenInput} />
|
<TextField value={websiteId} className={styles.hiddenInput} />
|
||||||
@ -73,28 +72,39 @@ export function FunnelForm({ onSearch }) {
|
|||||||
value={dateRange}
|
value={dateRange}
|
||||||
alignment="start"
|
alignment="start"
|
||||||
onChange={handleDateChange}
|
onChange={handleDateChange}
|
||||||
|
isF
|
||||||
/>
|
/>
|
||||||
<FormInput
|
<FormInput
|
||||||
name="startDate"
|
name="startAt"
|
||||||
className={styles.hiddenInput}
|
className={styles.hiddenInput}
|
||||||
rules={{ required: formatMessage(labels.required) }}
|
rules={{ required: formatMessage(labels.required) }}
|
||||||
>
|
>
|
||||||
<TextField value={startDate} />
|
<TextField value={startAt} />
|
||||||
</FormInput>
|
</FormInput>
|
||||||
<FormInput name="endDate" rules={{ required: formatMessage(labels.required) }}>
|
<FormInput name="endAt" rules={{ required: formatMessage(labels.required) }}>
|
||||||
<TextField value={endDate} className={styles.hiddenInput} />
|
<TextField value={endAt} className={styles.hiddenInput} />
|
||||||
|
</FormInput>
|
||||||
|
</FormRow>
|
||||||
|
<FormRow label="Window (minutes)">
|
||||||
|
<FormInput
|
||||||
|
name="window"
|
||||||
|
rules={{ required: formatMessage(labels.required), pattern: /[0-9]+/ }}
|
||||||
|
>
|
||||||
|
<TextField value={window} onChange={handleWindowChange} />
|
||||||
</FormInput>
|
</FormInput>
|
||||||
</FormRow>
|
</FormRow>
|
||||||
<Button onClick={handleAddUrl}>Add URL</Button>
|
<Button onClick={handleAddUrl}>Add URL</Button>
|
||||||
{urls.map((a, i) => (
|
{urls.map((a, i) => (
|
||||||
<FormRow key={`url${i}`} label={`URL ${i + 1}`}>
|
<FormRow className={styles.urlFormRow} key={`url${i}`} label={`URL ${i + 1}`}>
|
||||||
<Button onClick={() => handleRemoveUrl(i)}>Remove URL</Button>
|
|
||||||
<TextField value={urls[i]} onChange={value => handleUrlChange(value, i)} />
|
<TextField value={urls[i]} onChange={value => handleUrlChange(value, i)} />
|
||||||
|
<Button onClick={() => handleRemoveUrl(i)}>Remove URL</Button>
|
||||||
</FormRow>
|
</FormRow>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
<FormButtons>
|
<FormButtons>
|
||||||
<SubmitButton variant="primary">Search</SubmitButton>
|
<SubmitButton variant="primary" disabled={false}>
|
||||||
|
Search
|
||||||
|
</SubmitButton>
|
||||||
</FormButtons>
|
</FormButtons>
|
||||||
</Form>
|
</Form>
|
||||||
</>
|
</>
|
||||||
|
@ -17,3 +17,12 @@
|
|||||||
min-height: 0px;
|
min-height: 0px;
|
||||||
max-height: 0px;
|
max-height: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.urlFormRow {
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.urlFormRow label {
|
||||||
|
min-width: 80px;
|
||||||
|
}
|
||||||
|
@ -1,26 +1,38 @@
|
|||||||
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import Page from 'components/layout/Page';
|
import Page from 'components/layout/Page';
|
||||||
|
import PageHeader from 'components/layout/PageHeader';
|
||||||
|
import useApi from 'hooks/useApi';
|
||||||
|
import { useState } from 'react';
|
||||||
import FunnelChart from './FunnelChart';
|
import FunnelChart from './FunnelChart';
|
||||||
|
import FunnelTable from './FunnelTable';
|
||||||
import FunnelForm from './FunnelForm';
|
import FunnelForm from './FunnelForm';
|
||||||
|
import styles from './FunnelPage.module.css';
|
||||||
|
|
||||||
export default function FunnelPage() {
|
export default function FunnelPage() {
|
||||||
function handleOnSearch() {
|
const { post } = useApi();
|
||||||
|
const { mutate, error, isLoading } = useMutation(data => post('/reports/funnel', data));
|
||||||
|
const [data, setData] = useState();
|
||||||
|
|
||||||
|
function handleOnSearch(data) {
|
||||||
// do API CALL to api/reports/funnel to get funnelData
|
// do API CALL to api/reports/funnel to get funnelData
|
||||||
// Get DATA
|
// Get DATA
|
||||||
|
mutate(data, {
|
||||||
|
onSuccess: async data => {
|
||||||
|
setData(data);
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page>
|
<Page>
|
||||||
funnelPage
|
<PageHeader title="Funnel Report"></PageHeader>
|
||||||
|
<FunnelChart data={data} />
|
||||||
|
<FunnelTable data={data} />
|
||||||
{/* <ReportForm /> */}
|
{/* <ReportForm /> */}
|
||||||
<FunnelForm onSearchClick={handleOnSearch} /> website / start/endDate urls: []
|
<div>
|
||||||
<FunnelChart />
|
<h2>Filters</h2>
|
||||||
{/* {!chartLoaded && <Loading icon="dots" style={{ minHeight: 300 }} />}
|
<FunnelForm onSearch={handleOnSearch} />
|
||||||
{chartLoaded && (
|
</div>
|
||||||
<>
|
|
||||||
{!view && <WebsiteTableView websiteId={websiteId} />}
|
|
||||||
{view && <WebsiteMenuView websiteId={websiteId} />}
|
|
||||||
</>
|
|
||||||
)} */}
|
|
||||||
</Page>
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
10
components/pages/reports/FunnelPage.module.css
Normal file
10
components/pages/reports/FunnelPage.module.css
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
.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;
|
||||||
|
}
|
17
components/pages/reports/FunnelTable.js
Normal file
17
components/pages/reports/FunnelTable.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import DataTable from 'components/metrics/DataTable';
|
||||||
|
import useMessages from 'hooks/useMessages';
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
export function DevicesTable({ ...props }) {
|
||||||
|
const { formatMessage, labels } = useMessages();
|
||||||
|
const { data } = props;
|
||||||
|
|
||||||
|
const tableData =
|
||||||
|
data?.map(a => ({ x: a.url, y: a.count, z: (a.count / data[0].count) * 100 })) || [];
|
||||||
|
|
||||||
|
console.log(tableData);
|
||||||
|
|
||||||
|
return <DataTable data={tableData} title="Url" type="device" />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DevicesTable;
|
@ -17,9 +17,9 @@ model User {
|
|||||||
updatedAt DateTime? @updatedAt @map("updated_at") @db.Timestamptz(6)
|
updatedAt DateTime? @updatedAt @map("updated_at") @db.Timestamptz(6)
|
||||||
deletedAt DateTime? @map("deleted_at") @db.Timestamptz(6)
|
deletedAt DateTime? @map("deleted_at") @db.Timestamptz(6)
|
||||||
|
|
||||||
website Website[]
|
website Website[]
|
||||||
teamUser TeamUser[]
|
teamUser TeamUser[]
|
||||||
ReportTemplate UserReport[]
|
Report Report[]
|
||||||
|
|
||||||
@@map("user")
|
@@map("user")
|
||||||
}
|
}
|
||||||
@ -60,6 +60,7 @@ model Website {
|
|||||||
user User? @relation(fields: [userId], references: [id])
|
user User? @relation(fields: [userId], references: [id])
|
||||||
teamWebsite TeamWebsite[]
|
teamWebsite TeamWebsite[]
|
||||||
eventData EventData[]
|
eventData EventData[]
|
||||||
|
Report Report[]
|
||||||
|
|
||||||
@@index([userId])
|
@@index([userId])
|
||||||
@@index([createdAt])
|
@@index([createdAt])
|
||||||
@ -156,18 +157,21 @@ model TeamWebsite {
|
|||||||
@@map("team_website")
|
@@map("team_website")
|
||||||
}
|
}
|
||||||
|
|
||||||
model UserReport {
|
model Report {
|
||||||
id String @id() @unique() @map("report_id") @db.Uuid
|
id String @id() @unique() @map("report_id") @db.Uuid
|
||||||
userId String @map("user_id") @db.Uuid
|
userId String @map("user_id") @db.Uuid
|
||||||
websiteId String @map("website_id") @db.Uuid
|
websiteId String @map("website_id") @db.Uuid
|
||||||
reportName String @map("report_name") @db.VarChar(200)
|
type String @map("type") @db.VarChar(200)
|
||||||
templateName String @map("template_name") @db.VarChar(200)
|
name String @map("name") @db.VarChar(200)
|
||||||
parameters String @map("parameters") @db.VarChar(6000)
|
description String @map("description") @db.VarChar(500)
|
||||||
createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6)
|
parameters String @map("parameters") @db.VarChar(6000)
|
||||||
updatedAt DateTime? @updatedAt @map("updated_at") @db.Timestamptz(6)
|
createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6)
|
||||||
|
updatedAt DateTime? @updatedAt @map("updated_at") @db.Timestamptz(6)
|
||||||
|
|
||||||
user User @relation(fields: [userId], references: [id])
|
user User @relation(fields: [userId], references: [id])
|
||||||
|
website Website @relation(fields: [websiteId], references: [id])
|
||||||
|
|
||||||
@@index([userId])
|
@@index([userId])
|
||||||
@@map("user_report")
|
@@index([websiteId])
|
||||||
|
@@map("report")
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ export default async (
|
|||||||
startDate,
|
startDate,
|
||||||
endDate,
|
endDate,
|
||||||
urls,
|
urls,
|
||||||
windowMinutes: window,
|
windowMinutes: +window,
|
||||||
});
|
});
|
||||||
|
|
||||||
return ok(res, data);
|
return ok(res, data);
|
||||||
|
16
pages/settings/reports/funnel.js
Normal file
16
pages/settings/reports/funnel.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import AppLayout from 'components/layout/AppLayout';
|
||||||
|
import SettingsLayout from 'components/layout/SettingsLayout';
|
||||||
|
import FunnelPage from 'components/pages/reports/FunnelPage';
|
||||||
|
import useMessages from 'hooks/useMessages';
|
||||||
|
|
||||||
|
export default function DetailsPage() {
|
||||||
|
const { formatMessage, labels } = useMessages();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AppLayout title={`${formatMessage(labels.settings)} - ${formatMessage(labels.reports)}`}>
|
||||||
|
<SettingsLayout>
|
||||||
|
<FunnelPage />
|
||||||
|
</SettingsLayout>
|
||||||
|
</AppLayout>
|
||||||
|
);
|
||||||
|
}
|
@ -2,6 +2,7 @@ import { useRouter } from 'next/router';
|
|||||||
import AppLayout from 'components/layout/AppLayout';
|
import AppLayout from 'components/layout/AppLayout';
|
||||||
import FunnelPage from 'components/pages/reports/FunnelPage';
|
import FunnelPage from 'components/pages/reports/FunnelPage';
|
||||||
import useMessages from 'hooks/useMessages';
|
import useMessages from 'hooks/useMessages';
|
||||||
|
import SettingsLayout from 'components/layout/SettingsLayout';
|
||||||
|
|
||||||
export default function DetailsPage() {
|
export default function DetailsPage() {
|
||||||
// const { formatMessage, labels } = useMessages();
|
// const { formatMessage, labels } = useMessages();
|
||||||
@ -15,8 +16,10 @@ export default function DetailsPage() {
|
|||||||
// return <AppLayout title={formatMessage(labels.websites)}>{/* <FunnelPage /> */}</AppLayout>;
|
// return <AppLayout title={formatMessage(labels.websites)}>{/* <FunnelPage /> */}</AppLayout>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<AppLayout>
|
||||||
<FunnelPage />
|
<SettingsLayout>
|
||||||
</div>
|
<FunnelPage />
|
||||||
|
</SettingsLayout>
|
||||||
|
</AppLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user