Converted mutation queries.

This commit is contained in:
Mike Cao 2025-08-24 15:20:19 -07:00
parent 3f167e05ba
commit 0f9669f886
34 changed files with 259 additions and 350 deletions

View file

@ -9,14 +9,11 @@ import {
PasswordField,
Button,
} from '@umami/react-zen';
import { useApi, useMessages } from '@/components/hooks';
import { useMessages, useUpdateQuery } from '@/components/hooks';
import { ROLES } from '@/lib/constants';
export function UserAddForm({ onSave, onClose }) {
const { post, useMutation } = useApi();
const { mutate, error, isPending } = useMutation({
mutationFn: (data: any) => post(`/users`, data),
});
const { mutate, error, isPending } = useUpdateQuery(`/users`);
const { formatMessage, labels } = useMessages();
const handleSubmit = async (data: any) => {

View file

@ -1,5 +1,5 @@
import { AlertDialog, Row } from '@umami/react-zen';
import { useApi, useMessages, useModified } from '@/components/hooks';
import { useDeleteQuery, useMessages, useModified } from '@/components/hooks';
export function UserDeleteForm({
userId,
@ -13,8 +13,7 @@ export function UserDeleteForm({
onClose?: () => void;
}) {
const { messages, labels, formatMessage } = useMessages();
const { del, useMutation } = useApi();
const { mutate } = useMutation({ mutationFn: () => del(`/users/${userId}`) });
const { mutate } = useDeleteQuery(`/users/${userId}`);
const { touch } = useModified();
const handleConfirm = async () => {

View file

@ -7,30 +7,16 @@ import {
TextField,
FormSubmitButton,
PasswordField,
useToast,
} from '@umami/react-zen';
import { useApi, useLoginQuery, useMessages, useModified, useUser } from '@/components/hooks';
import { useLoginQuery, useMessages, useUpdateQuery, useUser } from '@/components/hooks';
import { ROLES } from '@/lib/constants';
export function UserEditForm({ userId, onSave }: { userId: string; onSave?: () => void }) {
const { formatMessage, labels, messages, getMessage } = useMessages();
const { post, useMutation } = useApi();
const user = useUser();
const { user: login } = useLoginQuery();
const { toast } = useToast();
const { touch } = useModified();
const { mutate, error } = useMutation({
mutationFn: ({
username,
password,
role,
}: {
username: string;
password: string;
role: string;
}) => post(`/users/${userId}`, { username, password, role }),
});
const { mutate, error, toast, touch } = useUpdateQuery(`/users/${userId}`);
const handleSubmit = async (data: any) => {
mutate(data, {

View file

@ -1,5 +1,5 @@
import { Form, FormField, FormSubmitButton, Row, TextField, Button } from '@umami/react-zen';
import { useApi } from '@/components/hooks';
import { useUpdateQuery } from '@/components/hooks';
import { DOMAIN_REGEX } from '@/lib/constants';
import { useMessages } from '@/components/hooks';
@ -13,10 +13,7 @@ export function BoardAddForm({
onClose?: () => void;
}) {
const { formatMessage, labels, messages } = useMessages();
const { post, useMutation } = useApi();
const { mutate, error, isPending } = useMutation({
mutationFn: (data: any) => post('/websites', { ...data, teamId }),
});
const { mutate, error, isPending } = useUpdateQuery('/websites', { teamId });
const handleSubmit = async (data: any) => {
mutate(data, {

View file

@ -3,7 +3,7 @@ import { ActionButton } from '@/components/input/ActionButton';
import { Trash } from '@/components/icons';
import { ConfirmationForm } from '@/components/common/ConfirmationForm';
import { messages } from '@/components/messages';
import { useApi, useMessages, useModified } from '@/components/hooks';
import { useDeleteQuery, useMessages } from '@/components/hooks';
export function LinkDeleteButton({
linkId,
@ -16,11 +16,7 @@ export function LinkDeleteButton({
onSave?: () => void;
}) {
const { formatMessage, labels } = useMessages();
const { del, useMutation } = useApi();
const { mutate, isPending, error } = useMutation({
mutationFn: () => del(`/links/${linkId}`),
});
const { touch } = useModified();
const { mutate, isPending, error, touch } = useDeleteQuery(`/links/${linkId}`);
const handleConfirm = (close: () => void) => {
mutate(null, {

View file

@ -3,8 +3,7 @@ import { ActionButton } from '@/components/input/ActionButton';
import { Trash } from '@/components/icons';
import { ConfirmationForm } from '@/components/common/ConfirmationForm';
import { messages } from '@/components/messages';
import { useApi, useMessages, useModified } from '@/components/hooks';
import { useDeleteQuery, useMessages, useModified } from '@/components/hooks';
export function PixelDeleteButton({
pixelId,
name,
@ -15,10 +14,7 @@ export function PixelDeleteButton({
onSave?: () => void;
}) {
const { formatMessage, labels } = useMessages();
const { del, useMutation } = useApi();
const { mutate, isPending, error } = useMutation({
mutationFn: () => del(`/pixels/${pixelId}`),
});
const { mutate, isPending, error } = useDeleteQuery(`/pixels/${pixelId}`);
const { touch } = useModified();
const handleConfirm = (close: () => void) => {

View file

@ -6,14 +6,11 @@ import {
Button,
FormSubmitButton,
} from '@umami/react-zen';
import { useApi, useMessages } from '@/components/hooks';
import { useMessages, useUpdateQuery } from '@/components/hooks';
export function PasswordEditForm({ onSave, onClose }) {
const { formatMessage, labels, messages } = useMessages();
const { post, useMutation } = useApi();
const { mutate, error, isPending } = useMutation({
mutationFn: (data: any) => post('/me/password', data),
});
const { mutate, error, isPending } = useUpdateQuery('/me/password');
const handleSubmit = async (data: any) => {
mutate(data, {

View file

@ -1,4 +1,4 @@
import { useApi, useMessages } from '@/components/hooks';
import { useMessages, useUpdateQuery } from '@/components/hooks';
import {
Button,
Form,
@ -10,10 +10,7 @@ import {
export function TeamAddForm({ onSave, onClose }: { onSave: () => void; onClose: () => void }) {
const { formatMessage, labels } = useMessages();
const { post, useMutation } = useApi();
const { mutate, error, isPending } = useMutation({
mutationFn: (data: any) => post('/teams', data),
});
const { mutate, error, isPending } = useUpdateQuery('/teams');
const handleSubmit = async (data: any) => {
mutate(data, {

View file

@ -6,12 +6,11 @@ import {
Button,
FormSubmitButton,
} from '@umami/react-zen';
import { useApi, useMessages, useModified } from '@/components/hooks';
import { useMessages, useModified, useUpdateQuery } from '@/components/hooks';
export function TeamJoinForm({ onSave, onClose }: { onSave: () => void; onClose: () => void }) {
const { formatMessage, labels } = useMessages();
const { post, useMutation } = useApi();
const { mutate, error } = useMutation({ mutationFn: (data: any) => post('/teams/join', data) });
const { mutate, error } = useUpdateQuery('/teams/join');
const { touch } = useModified();
const handleSubmit = async (data: any) => {

View file

@ -1,4 +1,4 @@
import { useApi, useMessages, useModified } from '@/components/hooks';
import { useDeleteQuery, useMessages, useModified } from '@/components/hooks';
import { ConfirmationForm } from '@/components/common/ConfirmationForm';
export function TeamLeaveForm({
@ -15,10 +15,7 @@ export function TeamLeaveForm({
onClose: () => void;
}) {
const { formatMessage, labels, messages } = useMessages();
const { del, useMutation } = useApi();
const { mutate, error, isPending } = useMutation({
mutationFn: () => del(`/teams/${teamId}/users/${userId}`),
});
const { mutate, error, isPending } = useDeleteQuery(`/teams/${teamId}/users/${userId}`);
const { touch } = useModified();
const handleConfirm = async () => {

View file

@ -1,5 +1,5 @@
import { TypeConfirmationForm } from '@/components/common/TypeConfirmationForm';
import { useApi, useMessages } from '@/components/hooks';
import { useDeleteQuery, useMessages } from '@/components/hooks';
const CONFIRM_VALUE = 'DELETE';
@ -13,14 +13,12 @@ export function TeamDeleteForm({
onClose?: () => void;
}) {
const { labels, formatMessage } = useMessages();
const { del, useMutation } = useApi();
const { mutate, error, isPending } = useMutation({
mutationFn: () => del(`/teams/${teamId}`),
});
const { mutate, error, isPending, touch } = useDeleteQuery(`/teams/${teamId}`);
const handleConfirm = async () => {
mutate(null, {
onSuccess: async () => {
touch('teams');
onSave?.();
onClose?.();
},

View file

@ -5,10 +5,9 @@ import {
FormSubmitButton,
TextField,
Button,
useToast,
} from '@umami/react-zen';
import { getRandomChars } from '@/lib/crypto';
import { useApi, useMessages, useModified, useTeam } from '@/components/hooks';
import { useMessages, useTeam, useUpdateQuery } from '@/components/hooks';
const generateId = () => `team_${getRandomChars(16)}`;
@ -23,20 +22,15 @@ export function TeamEditForm({
}) {
const team = useTeam();
const { formatMessage, labels, messages } = useMessages();
const { post, useMutation } = useApi();
const { toast } = useToast();
const { touch } = useModified();
const { mutate, error } = useMutation({
mutationFn: (data: any) => post(`/teams/${teamId}`, data),
});
const { mutate, error, isPending, touch, toast } = useUpdateQuery(`/teams/${teamId}`);
const handleSubmit = async (data: any) => {
mutate(data, {
onSuccess: async () => {
toast(formatMessage(messages.saved));
touch('teams');
touch(`teams:${teamId}`);
toast(formatMessage(messages.saved));
onSave?.();
},
});
@ -65,7 +59,9 @@ export function TeamEditForm({
<Button onPress={() => setValue('accessCode', generateId(), { shouldDirty: true })}>
{formatMessage(labels.regenerate)}
</Button>
<FormSubmitButton variant="primary">{formatMessage(labels.save)}</FormSubmitButton>
<FormSubmitButton variant="primary" isPending={isPending}>
{formatMessage(labels.save)}
</FormSubmitButton>
</FormButtons>
)}
</>

View file

@ -1,4 +1,4 @@
import { useApi, useMessages } from '@/components/hooks';
import { useMessages, useUpdateQuery } from '@/components/hooks';
import { ROLES } from '@/lib/constants';
import {
Button,
@ -23,10 +23,7 @@ export function TeamMemberEditForm({
onSave?: () => void;
onClose?: () => void;
}) {
const { post, useMutation } = useApi();
const { mutate, error, isPending } = useMutation({
mutationFn: (data: any) => post(`/teams/${teamId}/users/${userId}`, data),
});
const { mutate, error, isPending } = useUpdateQuery(`/teams/${teamId}/users/${userId}`);
const { formatMessage, labels } = useMessages();
const handleSubmit = async (data: any) => {

View file

@ -1,5 +1,5 @@
import { ConfirmationForm } from '@/components/common/ConfirmationForm';
import { useApi, useMessages, useModified } from '@/components/hooks';
import { useDeleteQuery, useMessages, useModified } from '@/components/hooks';
import { messages } from '@/components/messages';
import { Trash } from '@/components/icons';
import { Dialog } from '@umami/react-zen';
@ -18,10 +18,7 @@ export function TeamMemberRemoveButton({
onSave?: () => void;
}) {
const { formatMessage, labels } = useMessages();
const { del, useMutation } = useApi();
const { mutate, isPending, error } = useMutation({
mutationFn: () => del(`/teams/${teamId}/users/${userId}`),
});
const { mutate, isPending, error } = useDeleteQuery(`/teams/${teamId}/users/${userId}`);
const { touch } = useModified();
const handleConfirm = (close: () => void) => {

View file

@ -1,13 +1,10 @@
import { useApi, useMessages } from '@/components/hooks';
import { useDeleteQuery, useMessages } from '@/components/hooks';
import { Icon, LoadingButton, Text } from '@umami/react-zen';
import { Close } from '@/components/icons';
export function TeamWebsiteRemoveButton({ teamId, websiteId, onSave }) {
const { formatMessage, labels } = useMessages();
const { del, useMutation } = useApi();
const { mutate, isPending } = useMutation({
mutationFn: () => del(`/teams/${teamId}/websites/${websiteId}`),
});
const { mutate, isPending } = useDeleteQuery(`/teams/${teamId}/websites/${websiteId}`);
const handleRemoveTeamMember = async () => {
mutate(null, {

View file

@ -1,5 +1,5 @@
import { Form, FormField, FormSubmitButton, Row, TextField, Button } from '@umami/react-zen';
import { useApi } from '@/components/hooks';
import { useUpdateQuery } from '@/components/hooks';
import { DOMAIN_REGEX } from '@/lib/constants';
import { useMessages } from '@/components/hooks';
@ -13,10 +13,7 @@ export function WebsiteAddForm({
onClose?: () => void;
}) {
const { formatMessage, labels, messages } = useMessages();
const { post, useMutation } = useApi();
const { mutate, error, isPending } = useMutation({
mutationFn: (data: any) => post('/websites', { ...data, teamId }),
});
const { mutate, error, isPending } = useUpdateQuery('/websites', { teamId });
const handleSubmit = async (data: any) => {
mutate(data, {

View file

@ -15,7 +15,7 @@ import {
Row,
Loading,
} from '@umami/react-zen';
import { useApi, useMessages, useModified, useReportQuery } from '@/components/hooks';
import { useMessages, useReportQuery, useUpdateQuery } from '@/components/hooks';
import { File, Lightning, Close, Plus } from '@/components/icons';
const FUNNEL_STEPS_MAX = 8;
@ -32,12 +32,8 @@ export function FunnelEditForm({
onClose?: () => void;
}) {
const { formatMessage, labels } = useMessages();
const { touch } = useModified();
const { post, useMutation } = useApi();
const { data } = useReportQuery(id);
const { mutate, error, isPending } = useMutation({
mutationFn: (params: any) => post(`/reports${id ? `/${id}` : ''}`, params),
});
const { mutate, error, isPending, touch } = useUpdateQuery(`/reports${id ? `/${id}` : ''}`);
const handleSubmit = async ({ name, ...parameters }) => {
mutate(

View file

@ -12,7 +12,7 @@ import {
Icon,
Loading,
} from '@umami/react-zen';
import { useApi, useMessages, useModified, useReportQuery } from '@/components/hooks';
import { useMessages, useReportQuery, useUpdateQuery } from '@/components/hooks';
import { File, Lightning } from '@/components/icons';
export function GoalEditForm({
@ -27,12 +27,9 @@ export function GoalEditForm({
onClose?: () => void;
}) {
const { formatMessage, labels } = useMessages();
const { touch } = useModified();
const { post, useMutation } = useApi();
const { data } = useReportQuery(id);
const { mutate, error, isPending } = useMutation({
mutationFn: (params: any) => post(`/reports${id ? `/${id}` : ''}`, params),
});
const { mutate, error, isPending, touch } = useUpdateQuery(`/reports${id ? `/${id}` : ''}`);
const handleSubmit = async ({ name, ...parameters }) => {
mutate(

View file

@ -24,7 +24,11 @@ export function WebsiteNav({ websiteId }: { websiteId: string }) {
const { pathname, renderUrl, teamId } = useNavigation();
const renderPath = (path: string) =>
renderUrl(`/websites/${websiteId}${path}`, { event: undefined });
renderUrl(`/websites/${websiteId}${path}`, {
event: undefined,
compare: undefined,
view: undefined,
});
const items = [
{

View file

@ -3,7 +3,7 @@ import { ActionButton } from '@/components/input/ActionButton';
import { Trash } from '@/components/icons';
import { ConfirmationForm } from '@/components/common/ConfirmationForm';
import { messages } from '@/components/messages';
import { useApi, useMessages, useModified } from '@/components/hooks';
import { useDeleteQuery, useMessages } from '@/components/hooks';
export function CohortDeleteButton({
cohortId,
@ -17,11 +17,9 @@ export function CohortDeleteButton({
onSave?: () => void;
}) {
const { formatMessage, labels } = useMessages();
const { del, useMutation } = useApi();
const { mutate, isPending, error } = useMutation({
mutationFn: () => del(`/websites/${websiteId}/segments/${cohortId}`),
});
const { touch } = useModified();
const { mutate, isPending, error, touch } = useDeleteQuery(
`/websites/${websiteId}/segments/${cohortId}`,
);
const handleConfirm = (close: () => void) => {
mutate(null, {

View file

@ -11,7 +11,7 @@ import {
import { subMonths, endOfDay } from 'date-fns';
import { FieldFilters } from '@/components/input/FieldFilters';
import { useState } from 'react';
import { useApi, useMessages, useModified, useWebsiteCohortQuery } from '@/components/hooks';
import { useMessages, useUpdateQuery, useWebsiteCohortQuery } from '@/components/hooks';
import { filtersArrayToObject } from '@/lib/params';
export function CohortEditForm({
@ -30,26 +30,25 @@ export function CohortEditForm({
onClose?: () => void;
}) {
const { data } = useWebsiteCohortQuery(websiteId, cohortId);
const { formatMessage, labels } = useMessages();
const { formatMessage, labels, messages } = useMessages();
const [currentFilters, setCurrentFilters] = useState(filters);
const { touch } = useModified();
const startDate = subMonths(endOfDay(new Date()), 6);
const endDate = endOfDay(new Date());
const { post, useMutation } = useApi();
const { mutate, error, isPending } = useMutation({
mutationFn: (data: any) =>
post(`/websites/${websiteId}/cohorts${cohortId ? `/${cohortId}` : ''}`, {
...data,
type: 'cohort',
}),
});
const { mutate, error, isPending, touch, toast } = useUpdateQuery(
`/websites/${websiteId}/cohorts${cohortId ? `/${cohortId}` : ''}`,
{
...data,
type: 'cohort',
},
);
const handleSubmit = async (data: any) => {
mutate(
{ ...data, parameters: filtersArrayToObject(currentFilters) },
{
onSuccess: async () => {
toast(formatMessage(messages.save));
touch('cohorts');
onSave?.();
onClose?.();

View file

@ -17,80 +17,98 @@ export function CompareTables({ websiteId }: { websiteId: string }) {
updateParams,
query: { view = 'path' },
} = useNavigation();
const { startDate, endDate } = getCompareDate(
dateCompare,
dateRange.startDate,
dateRange.endDate,
);
const params = {
startAt: startDate.getTime(),
endAt: endDate.getTime(),
};
const renderPath = (view: string) => {
return updateParams({ view });
};
const items = [
{
id: 'path',
label: formatMessage(labels.path),
path: updateParams({ view: 'path' }),
path: renderPath('path'),
},
{
id: 'channel',
label: formatMessage(labels.channels),
path: renderPath('channel'),
},
{
id: 'referrer',
label: formatMessage(labels.referrers),
path: updateParams({ view: 'referrer' }),
path: renderPath('referrer'),
},
{
id: 'browser',
label: formatMessage(labels.browsers),
path: updateParams({ view: 'browser' }),
path: renderPath('browser'),
},
{
id: 'os',
label: formatMessage(labels.os),
path: updateParams({ view: 'os' }),
path: renderPath('os'),
},
{
id: 'device',
label: formatMessage(labels.devices),
path: updateParams({ view: 'device' }),
path: renderPath('device'),
},
{
id: 'country',
label: formatMessage(labels.countries),
path: updateParams({ view: 'country' }),
path: renderPath('country'),
},
{
id: 'region',
label: formatMessage(labels.regions),
path: updateParams({ view: 'region' }),
path: renderPath('region'),
},
{
id: 'city',
label: formatMessage(labels.cities),
path: updateParams({ view: 'city' }),
path: renderPath('city'),
},
{
id: 'language',
label: formatMessage(labels.languages),
path: updateParams({ view: 'language' }),
path: renderPath('language'),
},
{
id: 'screen',
label: formatMessage(labels.screens),
path: updateParams({ view: 'screen' }),
path: renderPath('screen'),
},
{
id: 'event',
label: formatMessage(labels.events),
path: updateParams({ view: 'event' }),
path: renderPath('event'),
},
{
id: 'hostname',
label: formatMessage(labels.hostname),
path: updateParams({ view: 'hostname' }),
path: renderPath('hostname'),
},
{
id: 'tag',
label: formatMessage(labels.tags),
path: updateParams({ view: 'tag' }),
path: renderPath('tag'),
},
];
const renderChange = props => {
const { label: x, count: y } = props;
const prev = data.find(d => d.x === x)?.y;
const value = y - prev;
const change = Math.abs(((y - prev) / prev) * 100);
const renderChange = ({ label, count }) => {
const prev = data.find(d => d.x === label)?.y;
const value = count - prev;
const change = Math.abs(((count - prev) / prev) * 100);
return (
!isNaN(change) && (
@ -101,19 +119,8 @@ export function CompareTables({ websiteId }: { websiteId: string }) {
);
};
const handleChange = id => {
router.push(updateParams({ view: id }));
};
const { startDate, endDate } = getCompareDate(
dateCompare,
dateRange.startDate,
dateRange.endDate,
);
const params = {
startAt: startDate.getTime(),
endAt: endDate.getTime(),
const handleChange = (id: any) => {
router.push(renderPath(id));
};
return (
@ -133,8 +140,8 @@ export function CompareTables({ websiteId }: { websiteId: string }) {
))}
</Select>
</Row>
<Panel>
<Grid columns={{ xs: '1fr', lg: '1fr 1fr' }} gap="6">
<Panel minHeight="300px">
<Grid columns={{ xs: '1fr', lg: '1fr 1fr' }} gap="6" height="100%">
<Column gap="6">
<Row alignItems="center" justifyContent="space-between">
<Heading size="2">{formatMessage(labels.previous)}</Heading>

View file

@ -3,7 +3,7 @@ import { ActionButton } from '@/components/input/ActionButton';
import { Trash } from '@/components/icons';
import { ConfirmationForm } from '@/components/common/ConfirmationForm';
import { messages } from '@/components/messages';
import { useApi, useMessages, useModified } from '@/components/hooks';
import { useDeleteQuery, useMessages } from '@/components/hooks';
export function SegmentDeleteButton({
segmentId,
@ -17,11 +17,9 @@ export function SegmentDeleteButton({
onSave?: () => void;
}) {
const { formatMessage, labels } = useMessages();
const { del, useMutation } = useApi();
const { mutate, isPending, error } = useMutation({
mutationFn: () => del(`/websites/${websiteId}/segments/${segmentId}`),
});
const { touch } = useModified();
const { mutate, isPending, error, touch } = useDeleteQuery(
`/websites/${websiteId}/segments/${segmentId}`,
);
const handleConfirm = (close: () => void) => {
mutate(null, {

View file

@ -1,4 +1,4 @@
import { useApi, useMessages, useModified } from '@/components/hooks';
import { useDeleteQuery, useMessages } from '@/components/hooks';
import { TypeConfirmationForm } from '@/components/common/TypeConfirmationForm';
const CONFIRM_VALUE = 'DELETE';
@ -13,11 +13,7 @@ export function WebsiteDeleteForm({
onClose?: () => void;
}) {
const { formatMessage, labels } = useMessages();
const { del, useMutation } = useApi();
const { mutate, isPending, error } = useMutation({
mutationFn: () => del(`/websites/${websiteId}`),
});
const { touch } = useModified();
const { mutate, isPending, error, touch } = useDeleteQuery(`/websites/${websiteId}`);
const handleConfirm = async () => {
mutate(null, {

View file

@ -1,24 +1,11 @@
import {
FormSubmitButton,
Form,
FormField,
FormButtons,
TextField,
useToast,
} from '@umami/react-zen';
import { useApi, useMessages, useModified, useWebsite } from '@/components/hooks';
import { FormSubmitButton, Form, FormField, FormButtons, TextField } from '@umami/react-zen';
import { useMessages, useUpdateQuery, useWebsite } from '@/components/hooks';
import { DOMAIN_REGEX } from '@/lib/constants';
export function WebsiteEditForm({ websiteId, onSave }: { websiteId: string; onSave?: () => void }) {
const website = useWebsite();
const { formatMessage, labels, messages } = useMessages();
const { post, useMutation } = useApi();
const { toast } = useToast();
const { touch } = useModified();
const { mutate, error } = useMutation({
mutationFn: (data: any) => post(`/websites/${websiteId}`, data),
});
const { mutate, error, touch, toast } = useUpdateQuery(`/websites/${websiteId}`);
const handleSubmit = async (data: any) => {
mutate(data, {

View file

@ -1,4 +1,4 @@
import { useApi, useMessages } from '@/components/hooks';
import { useMessages, useUpdateQuery } from '@/components/hooks';
import { TypeConfirmationForm } from '@/components/common/TypeConfirmationForm';
const CONFIRM_VALUE = 'RESET';
@ -13,10 +13,7 @@ export function WebsiteResetForm({
onClose?: () => void;
}) {
const { formatMessage, labels } = useMessages();
const { post, useMutation } = useApi();
const { mutate, isPending, error } = useMutation({
mutationFn: (data: any) => post(`/websites/${websiteId}/reset`, data),
});
const { mutate, isPending, error } = useUpdateQuery(`/websites/${websiteId}/reset`);
const handleConfirm = async () => {
mutate(null, {

View file

@ -7,12 +7,11 @@ import {
FormSubmitButton,
Column,
Label,
useToast,
Row,
} from '@umami/react-zen';
import { useState } from 'react';
import { getRandomChars } from '@/lib/crypto';
import { useApi, useMessages, useModified } from '@/components/hooks';
import { useMessages, useUpdateQuery } from '@/components/hooks';
const generateId = () => getRandomChars(16);
@ -26,12 +25,7 @@ export interface WebsiteShareFormProps {
export function WebsiteShareForm({ websiteId, shareId, onSave, onClose }: WebsiteShareFormProps) {
const { formatMessage, labels, messages } = useMessages();
const [id, setId] = useState(shareId);
const { post, useMutation } = useApi();
const { mutate, error, isPending } = useMutation({
mutationFn: (data: any) => post(`/websites/${websiteId}`, data),
});
const { touch } = useModified();
const { toast } = useToast();
const { mutate, error, isPending, touch, toast } = useUpdateQuery(`/websites/${websiteId}`);
const url = `${window?.location.origin || ''}${process.env.basePath || ''}/share/${id}`;

View file

@ -10,7 +10,7 @@ import {
Heading,
} from '@umami/react-zen';
import { useRouter } from 'next/navigation';
import { useApi, useMessages } from '@/components/hooks';
import { useMessages, useUpdateQuery } from '@/components/hooks';
import { setUser } from '@/store/app';
import { setClientAuthToken } from '@/lib/client';
import { Logo } from '@/components/icons';
@ -18,10 +18,7 @@ import { Logo } from '@/components/icons';
export function LoginForm() {
const { formatMessage, labels, getMessage } = useMessages();
const router = useRouter();
const { post, useMutation } = useApi();
const { mutate, error, isPending } = useMutation({
mutationFn: (data: any) => post('/auth/login', data),
});
const { mutate, error, isPending } = useUpdateQuery('/auth/login');
const handleSubmit = async (data: any) => {
mutate(data, {

View file

@ -2,10 +2,10 @@ import { useApi, useModified } from '@/components/hooks';
export function useDeleteQuery(path: string, params?: Record<string, any>) {
const { del, useMutation } = useApi();
const { mutate, isPending, error } = useMutation({
const query = useMutation({
mutationFn: () => del(path, params),
});
const { touch } = useModified();
return { mutate, isPending, error, touch };
return { ...query, touch };
}

View file

@ -4,11 +4,11 @@ import { useToast } from '@umami/react-zen';
export function useUpdateQuery(path: string, params?: Record<string, any>) {
const { post, useMutation } = useApi();
const { mutate, isPending, error } = useMutation({
const query = useMutation({
mutationFn: (data: Record<string, any>) => post(path, { ...data, ...params }),
});
const { touch } = useModified();
const { toast } = useToast();
return { mutate, isPending, error, touch, toast };
return { ...query, touch, toast };
}

View file

@ -68,13 +68,7 @@ export function MetricsTable({
};
return (
<LoadingPanel
data={data}
isFetching={isFetching}
isLoading={isLoading}
error={error}
height="100%"
>
<LoadingPanel data={data} isFetching={isFetching} isLoading={isLoading} error={error}>
{data && <ListTable {...props} data={filteredData} renderLabel={renderLabel} />}
{showMore && limit && (
<Row justifyContent="center">

View file

@ -31,6 +31,7 @@ export function PageviewsChart({ data, unit, minDate, maxDate, ...props }: Pagev
__id: new Date().getTime(),
datasets: [
{
type: data.compare ? 'line' : 'bar',
label: formatMessage(labels.visitors),
data: generateTimeSeries(data.sessions, minDate, maxDate, unit, dateLocale),
borderWidth: 1,
@ -40,6 +41,7 @@ export function PageviewsChart({ data, unit, minDate, maxDate, ...props }: Pagev
order: 3,
},
{
type: data.compare ? 'line' : 'bar',
label: formatMessage(labels.views),
data: generateTimeSeries(data.pageviews, minDate, maxDate, unit, dateLocale),
barPercentage: 0.9,