Refactored forms and pages.

This commit is contained in:
Mike Cao 2023-10-07 18:55:14 -07:00
parent 1325abe31d
commit 6253d55790
57 changed files with 209 additions and 208 deletions

View File

@ -60,7 +60,7 @@ const redirects = [
{ {
source: '/settings', source: '/settings',
destination: process.env.CLOUD_MODE destination: process.env.CLOUD_MODE
? `${process.env.CLOUD_URL}/settings/websites` ? `${process.env.CLOUD_URL}/websites`
: '/settings/websites', : '/settings/websites',
permanent: true, permanent: true,
}, },

View File

@ -0,0 +1,42 @@
import { Button, Icon, Icons, Modal, ModalTrigger, Text } from 'react-basics';
import ConfirmDeleteForm from 'components/common/ConfirmDeleteForm';
import { useApi, useMessages } from 'components/hooks';
import { setValue } from 'store/cache';
export function ReportDeleteButton({ reportId, reportName, onDelete }) {
const { formatMessage, labels } = useMessages();
const { del, useMutation } = useApi();
const { mutate } = useMutation(reportId => del(`/reports/${reportId}`));
const handleConfirm = close => {
mutate(reportId, {
onSuccess: () => {
setValue('reports', Date.now());
onDelete?.();
close();
},
});
};
return (
<ModalTrigger>
<Button>
<Icon>
<Icons.Trash />
</Icon>
<Text>{formatMessage(labels.delete)}</Text>
</Button>
<Modal>
{close => (
<ConfirmDeleteForm
name={reportName}
onConfirm={handleConfirm.bind(null, close)}
onClose={close}
/>
)}
</Modal>
</ModalTrigger>
);
}
export default ReportDeleteButton;

View File

@ -0,0 +1,22 @@
'use client';
import { useApi } from 'components/hooks';
import ReportsTable from './ReportsTable';
import useFilterQuery from 'components/hooks/useFilterQuery';
import DataTable from 'components/common/DataTable';
import useCache from 'store/cache';
function useReports() {
const { get } = useApi();
const modified = useCache(state => state?.reports);
return useFilterQuery(['reports', modified], params => get(`/reports`, params));
}
export default function ReportsDataTable() {
const queryResult = useReports();
return (
<DataTable queryResult={queryResult}>
{({ data }) => <ReportsTable data={data} showDomain={true} />}
</DataTable>
);
}

View File

@ -1,22 +1,23 @@
'use client'; 'use client';
import PageHeader from 'components/layout/PageHeader'; import PageHeader from 'components/layout/PageHeader';
import Link from 'next/link';
import { Button, Icon, Icons, Text } from 'react-basics'; import { Button, Icon, Icons, Text } from 'react-basics';
import { useMessages } from 'components/hooks'; import { useMessages } from 'components/hooks';
import { useRouter } from 'next/navigation';
export function ReportsHeader() { export function ReportsHeader() {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const router = useRouter();
const handleClick = () => router.push('/reports/create');
return ( return (
<PageHeader title={formatMessage(labels.reports)}> <PageHeader title={formatMessage(labels.reports)}>
<Link href="/reports/create"> <Button variant="primary" onClick={handleClick}>
<Button variant="primary"> <Icon>
<Icon> <Icons.Plus />
<Icons.Plus /> </Icon>
</Icon> <Text>{formatMessage(labels.createReport)}</Text>
<Text>{formatMessage(labels.createReport)}</Text> </Button>
</Button>
</Link>
</PageHeader> </PageHeader>
); );
} }

View File

@ -1,37 +0,0 @@
'use client';
import { useApi } from 'components/hooks';
import ReportsTable from './ReportsTable';
import useFilterQuery from 'components/hooks/useFilterQuery';
import DataTable from 'components/common/DataTable';
function useReports() {
const { get, del, useMutation } = useApi();
const { mutate } = useMutation(reportId => del(`/reports/${reportId}`));
const queryResult = useFilterQuery(['reports'], params => get(`/reports`, params));
const deleteReport = id => {
mutate(id, {
onSuccess: () => {
queryResult.refetch();
},
});
};
return { queryResult, deleteReport };
}
export default function ReportsList() {
const { queryResult, deleteReport } = useReports();
const handleDelete = async (id, callback) => {
await deleteReport(id);
await queryResult.refetch();
callback?.();
};
return (
<DataTable queryResult={queryResult}>
{({ data }) => <ReportsTable data={data} showDomain={true} onDelete={handleDelete} />}
</DataTable>
);
}

View File

@ -1,27 +1,14 @@
import ConfirmDeleteForm from 'components/common/ConfirmDeleteForm';
import LinkButton from 'components/common/LinkButton'; import LinkButton from 'components/common/LinkButton';
import { useMessages } from 'components/hooks'; import { useMessages } from 'components/hooks';
import useUser from 'components/hooks/useUser'; import useUser from 'components/hooks/useUser';
import { import { GridColumn, GridTable, Icon, Icons, Text } from 'react-basics';
Button,
GridColumn,
GridTable,
Icon,
Icons,
Modal,
ModalTrigger,
Text,
} from 'react-basics';
import { REPORT_TYPES } from 'lib/constants'; import { REPORT_TYPES } from 'lib/constants';
import ReportDeleteButton from './ReportDeleteButton';
export function ReportsTable({ data = [], onDelete, showDomain }) { export function ReportsTable({ data = [], showDomain }) {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { user } = useUser(); const { user } = useUser();
const handleConfirm = (id, callback) => {
onDelete?.(id, callback);
};
return ( return (
<GridTable data={data}> <GridTable data={data}>
<GridColumn name="name" label={formatMessage(labels.name)} /> <GridColumn name="name" label={formatMessage(labels.name)} />
@ -43,26 +30,15 @@ export function ReportsTable({ data = [], onDelete, showDomain }) {
const { id, name, userId, website } = row; const { id, name, userId, website } = row;
return ( return (
<> <>
<LinkButton href={`/reports/${id}`}>{formatMessage(labels.view)}</LinkButton>
{(user.id === userId || user.id === website?.userId) && ( {(user.id === userId || user.id === website?.userId) && (
<ModalTrigger> <ReportDeleteButton reportId={id} reportName={name} />
<Button>
<Icon>
<Icons.Trash />
</Icon>
<Text>{formatMessage(labels.delete)}</Text>
</Button>
<Modal>
{close => (
<ConfirmDeleteForm
name={name}
onConfirm={handleConfirm.bind(null, id, close)}
onClose={close}
/>
)}
</Modal>
</ModalTrigger>
)} )}
<LinkButton href={`/reports/${id}`}>
<Icon>
<Icons.ArrowRight />
</Icon>
<Text>{formatMessage(labels.view)}</Text>
</LinkButton>
</> </>
); );
}} }}

View File

@ -1,10 +1,10 @@
import { useContext } from 'react';
import { FormRow } from 'react-basics'; import { FormRow } from 'react-basics';
import { parseDateRange } from 'lib/date';
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 { parseDateRange } from 'lib/date';
import { useContext } from 'react';
import { ReportContext } from './Report';
import { useMessages } from 'components/hooks'; import { useMessages } from 'components/hooks';
import { ReportContext } from './Report';
export function BaseParameters({ export function BaseParameters({
showWebsiteSelect = true, showWebsiteSelect = true,

View File

@ -1,13 +1,13 @@
import { useContext, useRef } from 'react'; import { useContext, useRef } from 'react';
import { useApi, useMessages } from 'components/hooks';
import { Form, FormRow, FormButtons, SubmitButton, PopupTrigger, Icon, Popup } from 'react-basics'; import { Form, FormRow, FormButtons, SubmitButton, PopupTrigger, Icon, Popup } from 'react-basics';
import { ReportContext } from '../Report';
import Empty from 'components/common/Empty'; import Empty from 'components/common/Empty';
import { DATA_TYPES, REPORT_PARAMETERS } from 'lib/constants';
import Icons from 'components/icons'; import Icons from 'components/icons';
import FieldAddForm from '../FieldAddForm'; import { useApi, useMessages } from 'components/hooks';
import BaseParameters from '../BaseParameters'; import { DATA_TYPES, REPORT_PARAMETERS } from 'lib/constants';
import ParameterList from '../ParameterList'; import { ReportContext } from '../[id]/Report';
import FieldAddForm from '../[id]/FieldAddForm';
import ParameterList from '../[id]/ParameterList';
import BaseParameters from '../[id]/BaseParameters';
import styles from './EventDataParameters.module.css'; import styles from './EventDataParameters.module.css';
function useFields(websiteId, startDate, endDate) { function useFields(websiteId, startDate, endDate) {

View File

@ -1,7 +1,7 @@
import Report from '../Report'; import Report from '../[id]/Report';
import ReportHeader from '../ReportHeader'; import ReportHeader from '../[id]/ReportHeader';
import ReportMenu from '../ReportMenu'; import ReportMenu from '../[id]/ReportMenu';
import ReportBody from '../ReportBody'; import ReportBody from '../[id]/ReportBody';
import EventDataParameters from './EventDataParameters'; import EventDataParameters from './EventDataParameters';
import EventDataTable from './EventDataTable'; import EventDataTable from './EventDataTable';
import Nodes from 'assets/nodes.svg'; import Nodes from 'assets/nodes.svg';

View File

@ -1,7 +1,7 @@
import { useContext } from 'react'; import { useContext } from 'react';
import { GridTable, GridColumn } from 'react-basics'; import { GridTable, GridColumn } from 'react-basics';
import { useMessages } from 'components/hooks'; import { useMessages } from 'components/hooks';
import { ReportContext } from '../Report'; import { ReportContext } from '../[id]/Report';
export function EventDataTable() { export function EventDataTable() {
const { report } = useContext(ReportContext); const { report } = useContext(ReportContext);

View File

@ -5,7 +5,7 @@ import useTheme from 'components/hooks/useTheme';
import BarChart from 'components/metrics/BarChart'; import BarChart from 'components/metrics/BarChart';
import { formatLongNumber } from 'lib/format'; import { formatLongNumber } from 'lib/format';
import styles from './FunnelChart.module.css'; import styles from './FunnelChart.module.css';
import { ReportContext } from '../Report'; import { ReportContext } from '../[id]/Report';
export function FunnelChart({ className, loading }) { export function FunnelChart({ className, loading }) {
const { report } = useContext(ReportContext); const { report } = useContext(ReportContext);

View File

@ -13,10 +13,10 @@ import {
} from 'react-basics'; } from 'react-basics';
import Icons from 'components/icons'; import Icons from 'components/icons';
import UrlAddForm from './UrlAddForm'; import UrlAddForm from './UrlAddForm';
import { ReportContext } from '../Report'; import { ReportContext } from '../[id]/Report';
import BaseParameters from '../BaseParameters'; import BaseParameters from '../[id]/BaseParameters';
import ParameterList from '../ParameterList'; import ParameterList from '../[id]/ParameterList';
import PopupForm from '../PopupForm'; import PopupForm from '../[id]/PopupForm';
export function FunnelParameters() { export function FunnelParameters() {
const { report, runReport, updateReport, isRunning } = useContext(ReportContext); const { report, runReport, updateReport, isRunning } = useContext(ReportContext);

View File

@ -2,10 +2,10 @@
import FunnelChart from './FunnelChart'; import FunnelChart from './FunnelChart';
import FunnelTable from './FunnelTable'; import FunnelTable from './FunnelTable';
import FunnelParameters from './FunnelParameters'; import FunnelParameters from './FunnelParameters';
import Report from '../Report'; import Report from '../[id]/Report';
import ReportHeader from '../ReportHeader'; import ReportHeader from '../[id]/ReportHeader';
import ReportMenu from '../ReportMenu'; import ReportMenu from '../[id]/ReportMenu';
import ReportBody from '../ReportBody'; import ReportBody from '../[id]/ReportBody';
import Funnel from 'assets/funnel.svg'; import Funnel from 'assets/funnel.svg';
import { REPORT_TYPES } from 'lib/constants'; import { REPORT_TYPES } from 'lib/constants';

View File

@ -1,7 +1,7 @@
import { useContext } from 'react'; import { useContext } from 'react';
import ListTable from 'components/metrics/ListTable'; import ListTable from 'components/metrics/ListTable';
import { useMessages } from 'components/hooks'; import { useMessages } from 'components/hooks';
import { ReportContext } from '../Report'; import { ReportContext } from '../[id]/Report';
export function FunnelTable() { export function FunnelTable() {
const { report } = useContext(ReportContext); const { report } = useContext(ReportContext);

View File

@ -10,14 +10,14 @@ import {
Popup, Popup,
TooltipPopup, TooltipPopup,
} from 'react-basics'; } from 'react-basics';
import { ReportContext } from '../Report';
import Icons from 'components/icons'; import Icons from 'components/icons';
import BaseParameters from '../BaseParameters'; import BaseParameters from '../[id]/BaseParameters';
import ParameterList from '../ParameterList'; import { ReportContext } from '../[id]/Report';
import ParameterList from '../[id]/ParameterList';
import FilterSelectForm from '../[id]/FilterSelectForm';
import FieldSelectForm from '../[id]/FieldSelectForm';
import PopupForm from '../[id]/PopupForm';
import styles from './InsightsParameters.module.css'; import styles from './InsightsParameters.module.css';
import PopupForm from '../PopupForm';
import FilterSelectForm from '../FilterSelectForm';
import FieldSelectForm from '../FieldSelectForm';
export function InsightsParameters() { export function InsightsParameters() {
const { report, runReport, updateReport, isRunning } = useContext(ReportContext); const { report, runReport, updateReport, isRunning } = useContext(ReportContext);

View File

@ -1,8 +1,8 @@
'use client'; 'use client';
import Report from '../Report'; import Report from '../[id]/Report';
import ReportHeader from '../ReportHeader'; import ReportHeader from '../[id]/ReportHeader';
import ReportMenu from '../ReportMenu'; import ReportMenu from '../[id]/ReportMenu';
import ReportBody from '../ReportBody'; import ReportBody from '../[id]/ReportBody';
import InsightsParameters from './InsightsParameters'; import InsightsParameters from './InsightsParameters';
import InsightsTable from './InsightsTable'; import InsightsTable from './InsightsTable';
import Lightbulb from 'assets/lightbulb.svg'; import Lightbulb from 'assets/lightbulb.svg';

View File

@ -1,7 +1,7 @@
import { useContext, useEffect, useState } from 'react'; import { useContext, useEffect, useState } from 'react';
import { GridTable, GridColumn } from 'react-basics'; import { GridTable, GridColumn } from 'react-basics';
import { useFormat, useMessages } from 'components/hooks'; import { useFormat, useMessages } from 'components/hooks';
import { ReportContext } from '../Report'; import { ReportContext } from '../[id]/Report';
import EmptyPlaceholder from 'components/common/EmptyPlaceholder'; import EmptyPlaceholder from 'components/common/EmptyPlaceholder';
export function InsightsTable() { export function InsightsTable() {

View File

@ -1,11 +1,11 @@
import ReportsHeader from './ReportsHeader'; import ReportsHeader from './ReportsHeader';
import ReportsList from './ReportsList'; import ReportsDataTable from './ReportsDataTable';
export default function ReportsPage() { export default function ReportsPage() {
return ( return (
<> <>
<ReportsHeader /> <ReportsHeader />
<ReportsList /> <ReportsDataTable />
</> </>
); );
} }

View File

@ -1,9 +1,9 @@
import { useContext, useRef } from 'react'; import { useContext, useRef } from 'react';
import { useMessages } from 'components/hooks'; import { useMessages } from 'components/hooks';
import { Form, FormButtons, FormRow, SubmitButton } from 'react-basics'; import { Form, FormButtons, FormRow, SubmitButton } from 'react-basics';
import { ReportContext } from '../Report'; import { ReportContext } from '../[id]/Report';
import { MonthSelect } from 'components/input/MonthSelect'; import { MonthSelect } from 'components/input/MonthSelect';
import BaseParameters from '../BaseParameters'; import BaseParameters from '../[id]/BaseParameters';
import { parseDateRange } from 'lib/date'; import { parseDateRange } from 'lib/date';
export function RetentionParameters() { export function RetentionParameters() {

View File

@ -1,10 +1,10 @@
'use client'; 'use client';
import RetentionTable from './RetentionTable'; import RetentionTable from './RetentionTable';
import RetentionParameters from './RetentionParameters'; import RetentionParameters from './RetentionParameters';
import Report from '../Report'; import Report from '../[id]/Report';
import ReportHeader from '../ReportHeader'; import ReportHeader from '../[id]/ReportHeader';
import ReportMenu from '../ReportMenu'; import ReportMenu from '../[id]/ReportMenu';
import ReportBody from '../ReportBody'; import ReportBody from '../[id]/ReportBody';
import Magnet from 'assets/magnet.svg'; import Magnet from 'assets/magnet.svg';
import { REPORT_TYPES } from 'lib/constants'; import { REPORT_TYPES } from 'lib/constants';
import { parseDateRange } from 'lib/date'; import { parseDateRange } from 'lib/date';

View File

@ -1,9 +1,8 @@
import { useContext } from 'react'; import { useContext } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { ReportContext } from '../Report'; import { ReportContext } from '../[id]/Report';
import EmptyPlaceholder from 'components/common/EmptyPlaceholder'; import EmptyPlaceholder from 'components/common/EmptyPlaceholder';
import { useMessages } from 'components/hooks'; import { useMessages, useLocale } from 'components/hooks';
import { useLocale } from 'components/hooks';
import { formatDate } from 'lib/date'; import { formatDate } from 'lib/date';
import styles from './RetentionTable.module.css'; import styles from './RetentionTable.module.css';

View File

@ -8,6 +8,7 @@ import {
Button, Button,
SubmitButton, SubmitButton,
} from 'react-basics'; } from 'react-basics';
import { setValue } from 'store/cache';
import useApi from 'components/hooks/useApi'; import useApi from 'components/hooks/useApi';
import useMessages from 'components/hooks/useMessages'; import useMessages from 'components/hooks/useMessages';
@ -20,8 +21,9 @@ export function TeamAddForm({ onSave, onClose }) {
const handleSubmit = async data => { const handleSubmit = async data => {
mutate(data, { mutate(data, {
onSuccess: async () => { onSuccess: async () => {
onSave(); setValue('teams', Date.now());
onClose(); onSave?.();
onClose?.();
}, },
}); });
}; };

View File

@ -1,6 +1,7 @@
import { Button, Form, FormButtons, SubmitButton } from 'react-basics'; import { Button, Form, FormButtons, SubmitButton } from 'react-basics';
import useApi from 'components/hooks/useApi'; import useApi from 'components/hooks/useApi';
import useMessages from 'components/hooks/useMessages'; import useMessages from 'components/hooks/useMessages';
import { setValue } from 'store/cache';
export function TeamDeleteForm({ teamId, teamName, onSave, onClose }) { export function TeamDeleteForm({ teamId, teamName, onSave, onClose }) {
const { formatMessage, labels, messages, FormattedMessage } = useMessages(); const { formatMessage, labels, messages, FormattedMessage } = useMessages();
@ -10,8 +11,9 @@ export function TeamDeleteForm({ teamId, teamName, onSave, onClose }) {
const handleSubmit = async data => { const handleSubmit = async data => {
mutate(data, { mutate(data, {
onSuccess: async () => { onSuccess: async () => {
onSave(); setValue('teams', Date.now());
onClose(); onSave?.();
onClose?.();
}, },
}); });
}; };

View File

@ -25,16 +25,16 @@ export function TeamsTable({ data = [] }) {
return ( return (
<> <>
{showDelete && <TeamDeleteButton teamId={id} teamName={name} />}
{!showDelete && <TeamLeaveButton teamId={id} teamName={name} />}
<Link href={`/settings/teams/${id}`}> <Link href={`/settings/teams/${id}`}>
<Button> <Button>
<Icon> <Icon>
<Icons.Edit /> <Icons.Edit />
</Icon> </Icon>
<Text>{formatMessage(labels.view)}</Text> <Text>{formatMessage(labels.edit)}</Text>
</Button> </Button>
</Link> </Link>
{showDelete && <TeamDeleteButton teamId={id} teamName={name} />}
{!showDelete && <TeamLeaveButton teamId={id} teamName={name} />}
</> </>
); );
}} }}

View File

@ -4,7 +4,7 @@ import { Button, Form, FormButtons, GridColumn, Loading, SubmitButton, Toggle }
import useMessages from 'components/hooks/useMessages'; import useMessages from 'components/hooks/useMessages';
import WebsitesDataTable from '../../websites/WebsitesDataTable'; import WebsitesDataTable from '../../websites/WebsitesDataTable';
export function TeamAddWebsiteForm({ teamId, onSave, onClose }) { export function TeamWebsiteAddForm({ teamId, onSave, onClose }) {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { get, post, useQuery, useMutation } = useApi(); const { get, post, useQuery, useMutation } = useApi();
const { mutate, error } = useMutation(data => post(`/teams/${teamId}/websites`, data)); const { mutate, error } = useMutation(data => post(`/teams/${teamId}/websites`, data));
@ -57,4 +57,4 @@ export function TeamAddWebsiteForm({ teamId, onSave, onClose }) {
); );
} }
export default TeamAddWebsiteForm; export default TeamWebsiteAddForm;

View File

@ -7,15 +7,12 @@ export function TeamWebsiteRemoveButton({ teamId, websiteId, onSave }) {
const { del, useMutation } = useApi(); const { del, useMutation } = useApi();
const { mutate, isLoading } = useMutation(() => del(`/teams/${teamId}/websites/${websiteId}`)); const { mutate, isLoading } = useMutation(() => del(`/teams/${teamId}/websites/${websiteId}`));
const handleRemoveTeamMember = () => { const handleRemoveTeamMember = async () => {
mutate( await mutate(null, {
{}, onSuccess: () => {
{ onSave();
onSuccess: () => {
onSave();
},
}, },
); });
}; };
return ( return (

View File

@ -1,6 +1,6 @@
import { ActionForm, Button, Icon, Icons, Modal, ModalTrigger, Text } from 'react-basics'; import { ActionForm, Button, Icon, Icons, Modal, ModalTrigger, Text } from 'react-basics';
import TeamWebsitesTable from './TeamWebsitesTable'; import TeamWebsitesTable from './TeamWebsitesTable';
import TeamAddWebsiteForm from './TeamAddWebsiteForm'; import TeamWebsiteAddForm from './TeamWebsiteAddForm';
import useApi from 'components/hooks/useApi'; import useApi from 'components/hooks/useApi';
import useMessages from 'components/hooks/useMessages'; import useMessages from 'components/hooks/useMessages';
import useUser from 'components/hooks/useUser'; import useUser from 'components/hooks/useUser';
@ -36,7 +36,7 @@ export function TeamWebsites({ teamId }) {
<Text>{formatMessage(labels.addWebsite)}</Text> <Text>{formatMessage(labels.addWebsite)}</Text>
</Button> </Button>
<Modal title={formatMessage(labels.addWebsite)}> <Modal title={formatMessage(labels.addWebsite)}>
{close => <TeamAddWebsiteForm teamId={teamId} onSave={handleChange} onClose={close} />} {close => <TeamWebsiteAddForm teamId={teamId} onSave={handleChange} onClose={close} />}
</Modal> </Modal>
</ModalTrigger> </ModalTrigger>
</ActionForm> </ActionForm>

View File

@ -1,6 +1,7 @@
import { Button, Icon, Icons, Modal, ModalTrigger, Text, useToasts } from 'react-basics'; import { Button, Icon, Icons, Modal, ModalTrigger, Text, useToasts } from 'react-basics';
import WebsiteAddForm from './WebsiteAddForm'; import WebsiteAddForm from './WebsiteAddForm';
import useMessages from 'components/hooks/useMessages'; import useMessages from 'components/hooks/useMessages';
import { setValue } from 'store/cache';
export function WebsiteAddButton({ onSave }) { export function WebsiteAddButton({ onSave }) {
const { formatMessage, labels, messages } = useMessages(); const { formatMessage, labels, messages } = useMessages();
@ -8,6 +9,7 @@ export function WebsiteAddButton({ onSave }) {
const handleSave = async () => { const handleSave = async () => {
showToast({ message: formatMessage(messages.saved), variant: 'success' }); showToast({ message: formatMessage(messages.saved), variant: 'success' });
setValue('websites', Date.now());
onSave?.(); onSave?.();
}; };

View File

@ -4,13 +4,15 @@ import useUser from 'components/hooks/useUser';
import useApi from 'components/hooks/useApi'; import useApi from 'components/hooks/useApi';
import DataTable from 'components/common/DataTable'; import DataTable from 'components/common/DataTable';
import useFilterQuery from 'components/hooks/useFilterQuery'; import useFilterQuery from 'components/hooks/useFilterQuery';
import WebsitesHeader from './WebsitesHeader'; import useCache from 'store/cache';
function useWebsites({ includeTeams, onlyTeams }) { function useWebsites({ includeTeams, onlyTeams }) {
const { user } = useUser(); const { user } = useUser();
const { get } = useApi(); const { get } = useApi();
const modified = useCache(state => state?.websites);
return useFilterQuery( return useFilterQuery(
['websites', { includeTeams, onlyTeams }], ['websites', { includeTeams, onlyTeams, modified }],
params => { params => {
return get(`/users/${user?.id}/websites`, { return get(`/users/${user?.id}/websites`, {
includeTeams, includeTeams,
@ -23,9 +25,8 @@ function useWebsites({ includeTeams, onlyTeams }) {
} }
export function WebsitesDataTable({ export function WebsitesDataTable({
showHeader = true, allowEdit = true,
showEditButton = true, allowView = true,
showViewButton = true,
showActions = true, showActions = true,
showTeam, showTeam,
includeTeams, includeTeams,
@ -35,22 +36,19 @@ export function WebsitesDataTable({
const queryResult = useWebsites({ includeTeams, onlyTeams }); const queryResult = useWebsites({ includeTeams, onlyTeams });
return ( return (
<> <DataTable queryResult={queryResult}>
{showHeader && <WebsitesHeader />} {({ data }) => (
<DataTable queryResult={queryResult}> <WebsitesTable
{({ data }) => ( data={data}
<WebsitesTable showTeam={showTeam}
data={data} showActions={showActions}
showTeam={showTeam} allowEdit={allowEdit}
showActions={showActions} allowView={allowView}
showEditButton={showEditButton} >
showViewButton={showViewButton} {children}
> </WebsitesTable>
{children} )}
</WebsitesTable> </DataTable>
)}
</DataTable>
</>
); );
} }

View File

@ -7,8 +7,8 @@ export function WebsitesTable({
data = [], data = [],
showTeam, showTeam,
showActions, showActions,
showEditButton, allowEdit,
showViewButton, allowView,
children, children,
}) { }) {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
@ -37,7 +37,7 @@ export function WebsitesTable({
return ( return (
<> <>
{showActions && showEditButton && (!showTeam || ownerId === user.id) && ( {showActions && allowEdit && (!showTeam || ownerId === user.id) && (
<Link href={`/settings/websites/${id}`}> <Link href={`/settings/websites/${id}`}>
<Button> <Button>
<Icon> <Icon>
@ -47,7 +47,7 @@ export function WebsitesTable({
</Button> </Button>
</Link> </Link>
)} )}
{showActions && showViewButton && ( {showActions && allowView && (
<Link href={`/websites/${id}`}> <Link href={`/websites/${id}`}>
<Button> <Button>
<Icon> <Icon>

View File

@ -1,9 +1,15 @@
import WebsitesDataTable from './WebsitesDataTable'; import WebsitesDataTable from './WebsitesDataTable';
import WebsitesHeader from './WebsitesHeader';
export default function () { export default function () {
if (process.env.cloudMode) { if (process.env.cloudMode) {
return null; return null;
} }
return <WebsitesDataTable />; return (
<>
<WebsitesHeader />
<WebsitesDataTable />
</>
);
} }

View File

@ -3,8 +3,8 @@ import { useApi, useDateRange, useMessages, useNavigation, useSticky } from 'com
import WebsiteDateFilter from 'components/input/WebsiteDateFilter'; import WebsiteDateFilter from 'components/input/WebsiteDateFilter';
import MetricCard from 'components/metrics/MetricCard'; import MetricCard from 'components/metrics/MetricCard';
import MetricsBar from 'components/metrics/MetricsBar'; import MetricsBar from 'components/metrics/MetricsBar';
import FilterSelectForm from '../../../(main)/reports/FilterSelectForm'; import FilterSelectForm from 'app/(main)/reports/[id]/FilterSelectForm';
import PopupForm from '../../../(main)/reports/PopupForm'; import PopupForm from 'app/(main)/reports/[id]/PopupForm';
import { formatShortTime } from 'lib/format'; import { formatShortTime } from 'lib/format';
import { Button, Icon, Icons, Popup, PopupTrigger } from 'react-basics'; import { Button, Icon, Icons, Popup, PopupTrigger } from 'react-basics';
import styles from './WebsiteMetricsBar.module.css'; import styles from './WebsiteMetricsBar.module.css';

View File

@ -2,7 +2,7 @@
import { Flexbox } from 'react-basics'; import { Flexbox } from 'react-basics';
import useMessages from 'components/hooks/useMessages'; import useMessages from 'components/hooks/useMessages';
export default function Custom404() { export default function () {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
return ( return (

View File

@ -1,16 +1,14 @@
import classNames from 'classnames'; import classNames from 'classnames';
import Link from 'next/link'; import Link from 'next/link';
import { Icon, Icons, Text } from 'react-basics';
import styles from './LinkButton.module.css';
import { useLocale } from 'components/hooks'; import { useLocale } from 'components/hooks';
import styles from './LinkButton.module.css';
export function LinkButton({ href, icon, className, children }) { export function LinkButton({ href, className, children }) {
const { dir } = useLocale(); const { dir } = useLocale();
return ( return (
<Link className={classNames(styles.button, className)} href={href}> <Link className={classNames(styles.button, className)} href={href} dir={dir}>
<Icon rotate={dir === 'rtl' ? 0 : 180}>{icon || <Icons.ArrowRight />}</Icon> {children}
<Text>{children}</Text>
</Link> </Link>
); );
} }

View File

@ -2,7 +2,6 @@
flex: 1; flex: 1;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background: var(--base50);
position: relative; position: relative;
max-width: 1320px; max-width: 1320px;
min-height: calc(100vh - 60px); min-height: calc(100vh - 60px);

View File

@ -22,29 +22,31 @@ export * from 'components/hooks/useUser';
export * from 'components/hooks/useWebsite'; export * from 'components/hooks/useWebsite';
export * from 'components/hooks/useWebsiteReports'; export * from 'components/hooks/useWebsiteReports';
export * from 'app/(main)/settings/teams/TeamAddForm'; export * from './app/(main)/settings/teams/[id]/TeamWebsiteAddForm';
export * from 'app/(main)/settings/teams/[id]/TeamAddWebsiteForm';
export * from 'app/(main)/settings/teams/TeamDeleteForm';
export * from 'app/(main)/settings/teams/[id]/TeamEditForm'; export * from 'app/(main)/settings/teams/[id]/TeamEditForm';
export * from 'app/(main)/settings/teams/TeamJoinForm';
export * from 'app/(main)/settings/teams/TeamLeaveForm';
export * from 'app/(main)/settings/teams/[id]/TeamMemberRemoveButton'; export * from 'app/(main)/settings/teams/[id]/TeamMemberRemoveButton';
export * from 'app/(main)/settings/teams/[id]/TeamMembers'; export * from 'app/(main)/settings/teams/[id]/TeamMembers';
export * from 'app/(main)/settings/teams/[id]/TeamMembersTable'; export * from 'app/(main)/settings/teams/[id]/TeamMembersTable';
export * from 'app/(main)/settings/teams/[id]/TeamSettings'; export * from 'app/(main)/settings/teams/[id]/TeamSettings';
export * from 'app/(main)/settings/teams/TeamsDataTable';
export * from 'app/(main)/settings/teams/TeamsTable';
export * from 'app/(main)/settings/teams/[id]/TeamWebsiteRemoveButton'; export * from 'app/(main)/settings/teams/[id]/TeamWebsiteRemoveButton';
export * from 'app/(main)/settings/teams/[id]/TeamWebsites'; export * from 'app/(main)/settings/teams/[id]/TeamWebsites';
export * from 'app/(main)/settings/teams/[id]/TeamWebsitesTable'; export * from 'app/(main)/settings/teams/[id]/TeamWebsitesTable';
export * from 'app/(main)/settings/teams/TeamAddForm';
export * from 'app/(main)/settings/teams/TeamDeleteForm';
export * from 'app/(main)/settings/teams/TeamsHeader';
export * from 'app/(main)/settings/teams/TeamJoinForm';
export * from 'app/(main)/settings/teams/TeamLeaveForm';
export * from 'app/(main)/settings/teams/TeamsDataTable';
export * from 'app/(main)/settings/teams/TeamsTable';
export * from 'app/(main)/settings/teams/WebsiteTags'; export * from 'app/(main)/settings/teams/WebsiteTags';
export * from 'app/(main)/settings/websites/[id]/ShareUrl'; export * from 'app/(main)/settings/websites/[id]/ShareUrl';
export * from 'app/(main)/settings/websites/[id]/TrackingCode'; export * from 'app/(main)/settings/websites/[id]/TrackingCode';
export * from 'app/(main)/settings/websites/WebsiteAddForm';
export * from 'app/(main)/settings/websites/[id]/WebsiteDeleteForm'; export * from 'app/(main)/settings/websites/[id]/WebsiteDeleteForm';
export * from 'app/(main)/settings/websites/[id]/WebsiteEditForm'; export * from 'app/(main)/settings/websites/[id]/WebsiteEditForm';
export * from 'app/(main)/settings/websites/[id]/WebsiteResetForm'; export * from 'app/(main)/settings/websites/[id]/WebsiteResetForm';
export * from 'app/(main)/settings/websites/WebsiteAddForm';
export * from 'app/(main)/settings/websites/WebsitesHeader';
export * from 'app/(main)/settings/websites/WebsiteSettings'; export * from 'app/(main)/settings/websites/WebsiteSettings';
export * from 'app/(main)/settings/websites/WebsitesDataTable'; export * from './app/(main)/settings/websites/WebsitesDataTable';
export * from 'app/(main)/settings/websites/WebsitesTable'; export * from 'app/(main)/settings/websites/WebsitesTable';

9
src/store/cache.js Normal file
View File

@ -0,0 +1,9 @@
import { create } from 'zustand';
const store = create(() => ({}));
export function setValue(key, value) {
store.setState({ [key]: value });
}
export default store;

View File

@ -1,13 +0,0 @@
import { create } from 'zustand';
const store = create(() => ({}));
export function saveQuery(key, data) {
store.setState({ [key]: data });
}
export function getQuery(key) {
return store.getState()[key];
}
export default store;

View File

@ -4,10 +4,6 @@ import { DateRange } from 'lib/types';
const store = create(() => ({})); const store = create(() => ({}));
export function getWebsiteDateRange(websiteId: string) {
return store.getState()?.[websiteId];
}
export function setWebsiteDateRange(websiteId: string, dateRange: DateRange) { export function setWebsiteDateRange(websiteId: string, dateRange: DateRange) {
store.setState( store.setState(
produce(state => { produce(state => {