mirror of
https://github.com/kremalicious/umami.git
synced 2025-02-14 21:10:34 +01:00
Updated website, team and user save.
This commit is contained in:
parent
2fa50892d8
commit
fec81695e8
@ -4,6 +4,7 @@ import { Item, Loading, Tabs, Flexbox } from 'react-basics';
|
|||||||
import TeamsContext from 'app/(main)/teams/TeamsContext';
|
import TeamsContext from 'app/(main)/teams/TeamsContext';
|
||||||
import PageHeader from 'components/layout/PageHeader';
|
import PageHeader from 'components/layout/PageHeader';
|
||||||
import { ROLES } from 'lib/constants';
|
import { ROLES } from 'lib/constants';
|
||||||
|
import Icons from 'components/icons';
|
||||||
import { useLogin, useTeam, useMessages } from 'components/hooks';
|
import { useLogin, useTeam, useMessages } from 'components/hooks';
|
||||||
import TeamEditForm from './TeamEditForm';
|
import TeamEditForm from './TeamEditForm';
|
||||||
import TeamMembers from './TeamMembers';
|
import TeamMembers from './TeamMembers';
|
||||||
@ -27,7 +28,7 @@ export function TeamSettings({ teamId }: { teamId: string }) {
|
|||||||
return (
|
return (
|
||||||
<TeamsContext.Provider value={team}>
|
<TeamsContext.Provider value={team}>
|
||||||
<Flexbox direction="column">
|
<Flexbox direction="column">
|
||||||
<PageHeader title={team?.name} />
|
<PageHeader title={team?.name} icon={<Icons.Users />} />
|
||||||
<Tabs
|
<Tabs
|
||||||
selectedKey={tab}
|
selectedKey={tab}
|
||||||
onSelect={(value: any) => setTab(value)}
|
onSelect={(value: any) => setTab(value)}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import DataTable from 'components/common/DataTable';
|
import DataTable from 'components/common/DataTable';
|
||||||
|
import { useUsers } from 'components/hooks';
|
||||||
import UsersTable from './UsersTable';
|
import UsersTable from './UsersTable';
|
||||||
import useUsers from 'components/hooks/queries/useUsers';
|
|
||||||
|
|
||||||
export function UsersDataTable({ showActions }: { showActions?: boolean }) {
|
export function UsersDataTable({ showActions }: { showActions?: boolean }) {
|
||||||
const queryResult = useUsers();
|
const queryResult = useUsers();
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import { Key, useState } from 'react';
|
import { Key, useState } from 'react';
|
||||||
import { Item, Loading, Tabs } from 'react-basics';
|
import { Item, Loading, Tabs } from 'react-basics';
|
||||||
|
import Icons from 'components/icons';
|
||||||
import UserEditForm from '../UserEditForm';
|
import UserEditForm from '../UserEditForm';
|
||||||
import PageHeader from 'components/layout/PageHeader';
|
import PageHeader from 'components/layout/PageHeader';
|
||||||
import { useMessages, useUser } from 'components/hooks';
|
import { useMessages, useUser } from 'components/hooks';
|
||||||
@ -17,7 +18,7 @@ export function UserSettings({ userId }: { userId: string }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageHeader title={user?.username} />
|
<PageHeader title={user?.username} icon={<Icons.User />} />
|
||||||
<Tabs selectedKey={tab} onSelect={setTab} style={{ marginBottom: 30, fontSize: 14 }}>
|
<Tabs selectedKey={tab} onSelect={setTab} style={{ marginBottom: 30, fontSize: 14 }}>
|
||||||
<Item key="details">{formatMessage(labels.details)}</Item>
|
<Item key="details">{formatMessage(labels.details)}</Item>
|
||||||
<Item key="websites">{formatMessage(labels.websites)}</Item>
|
<Item key="websites">{formatMessage(labels.websites)}</Item>
|
||||||
|
@ -10,8 +10,6 @@ import {
|
|||||||
import { useApi } from 'components/hooks';
|
import { useApi } from 'components/hooks';
|
||||||
import { DOMAIN_REGEX } from 'lib/constants';
|
import { DOMAIN_REGEX } from 'lib/constants';
|
||||||
import { useMessages } from 'components/hooks';
|
import { useMessages } from 'components/hooks';
|
||||||
import { useContext } from 'react';
|
|
||||||
import SettingsContext from '../SettingsContext';
|
|
||||||
|
|
||||||
export function WebsiteAddForm({
|
export function WebsiteAddForm({
|
||||||
teamId,
|
teamId,
|
||||||
@ -23,10 +21,9 @@ export function WebsiteAddForm({
|
|||||||
onClose?: () => void;
|
onClose?: () => void;
|
||||||
}) {
|
}) {
|
||||||
const { formatMessage, labels, messages } = useMessages();
|
const { formatMessage, labels, messages } = useMessages();
|
||||||
const { websitesUrl } = useContext(SettingsContext);
|
|
||||||
const { post, useMutation } = useApi();
|
const { post, useMutation } = useApi();
|
||||||
const { mutate, error, isPending } = useMutation({
|
const { mutate, error, isPending } = useMutation({
|
||||||
mutationFn: (data: any) => post(websitesUrl, { ...data, teamId }),
|
mutationFn: (data: any) => post('/websites', { ...data, teamId }),
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleSubmit = async (data: any) => {
|
const handleSubmit = async (data: any) => {
|
||||||
|
@ -1,39 +1,23 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import { useState, Key } from 'react';
|
import { useState, Key } from 'react';
|
||||||
import { Item, Tabs, useToasts, Button, Text, Icon, Icons, Loading } from 'react-basics';
|
import { Item, Tabs, Button, Text, Icon, Loading } from 'react-basics';
|
||||||
import { useRouter } from 'next/navigation';
|
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
import Icons from 'components/icons';
|
||||||
import PageHeader from 'components/layout/PageHeader';
|
import PageHeader from 'components/layout/PageHeader';
|
||||||
import WebsiteEditForm from './[id]/WebsiteEditForm';
|
import WebsiteEditForm from './[id]/WebsiteEditForm';
|
||||||
import WebsiteData from './[id]/WebsiteData';
|
import WebsiteData from './[id]/WebsiteData';
|
||||||
import TrackingCode from './[id]/TrackingCode';
|
import TrackingCode from './[id]/TrackingCode';
|
||||||
import ShareUrl from './[id]/ShareUrl';
|
import ShareUrl from './[id]/ShareUrl';
|
||||||
import { useWebsite, useMessages } from 'components/hooks';
|
import { useWebsite, useMessages } from 'components/hooks';
|
||||||
import { touch } from 'store/cache';
|
import WebsiteContext from 'app/(main)/websites/[id]/WebsiteContext';
|
||||||
|
|
||||||
export function WebsiteSettings({ websiteId, openExternal = false }) {
|
export function WebsiteSettings({ websiteId, openExternal = false }) {
|
||||||
const router = useRouter();
|
const { formatMessage, labels } = useMessages();
|
||||||
const { formatMessage, labels, messages } = useMessages();
|
const { data: website, isLoading, refetch } = useWebsite(websiteId, { gcTime: 0 });
|
||||||
const { showToast } = useToasts();
|
|
||||||
|
|
||||||
const { data: website, isLoading } = useWebsite(websiteId, { gcTime: 0 });
|
|
||||||
const [tab, setTab] = useState<Key>('details');
|
const [tab, setTab] = useState<Key>('details');
|
||||||
|
|
||||||
const showSuccess = () => {
|
|
||||||
showToast({ message: formatMessage(messages.saved), variant: 'success' });
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
showSuccess();
|
refetch();
|
||||||
touch('websites');
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleReset = async (value: string) => {
|
|
||||||
if (value === 'delete') {
|
|
||||||
router.push('/settings/websites');
|
|
||||||
} else if (value === 'reset') {
|
|
||||||
showSuccess();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
@ -41,8 +25,8 @@ export function WebsiteSettings({ websiteId, openExternal = false }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<WebsiteContext.Provider value={website}>
|
||||||
<PageHeader title={website?.name}>
|
<PageHeader title={website?.name} icon={<Icons.Globe />}>
|
||||||
<Link href={`/websites/${websiteId}`} target={openExternal ? '_blank' : null}>
|
<Link href={`/websites/${websiteId}`} target={openExternal ? '_blank' : null}>
|
||||||
<Button variant="primary">
|
<Button variant="primary">
|
||||||
<Icon>
|
<Icon>
|
||||||
@ -58,13 +42,11 @@ export function WebsiteSettings({ websiteId, openExternal = false }) {
|
|||||||
<Item key="share">{formatMessage(labels.shareUrl)}</Item>
|
<Item key="share">{formatMessage(labels.shareUrl)}</Item>
|
||||||
<Item key="data">{formatMessage(labels.data)}</Item>
|
<Item key="data">{formatMessage(labels.data)}</Item>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
{tab === 'details' && (
|
{tab === 'details' && <WebsiteEditForm website={website} onSave={handleSave} />}
|
||||||
<WebsiteEditForm websiteId={websiteId} data={website} onSave={handleSave} />
|
|
||||||
)}
|
|
||||||
{tab === 'tracking' && <TrackingCode websiteId={websiteId} />}
|
{tab === 'tracking' && <TrackingCode websiteId={websiteId} />}
|
||||||
{tab === 'share' && <ShareUrl websiteId={websiteId} data={website} onSave={handleSave} />}
|
{tab === 'share' && <ShareUrl website={website} onSave={handleSave} />}
|
||||||
{tab === 'data' && <WebsiteData websiteId={websiteId} onSave={handleReset} />}
|
{tab === 'data' && <WebsiteData websiteId={websiteId} />}
|
||||||
</>
|
</WebsiteContext.Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,16 +2,7 @@
|
|||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
import WebsitesTable from 'app/(main)/settings/websites/WebsitesTable';
|
import WebsitesTable from 'app/(main)/settings/websites/WebsitesTable';
|
||||||
import DataTable from 'components/common/DataTable';
|
import DataTable from 'components/common/DataTable';
|
||||||
import useWebsites from 'components/hooks/queries/useWebsites';
|
import { useWebsites } from 'components/hooks';
|
||||||
|
|
||||||
export interface WebsitesDataTableProps {
|
|
||||||
userId?: string;
|
|
||||||
teamId?: string;
|
|
||||||
allowEdit?: boolean;
|
|
||||||
allowView?: boolean;
|
|
||||||
showActions?: boolean;
|
|
||||||
children?: ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WebsitesDataTable({
|
export function WebsitesDataTable({
|
||||||
userId,
|
userId,
|
||||||
@ -20,13 +11,21 @@ export function WebsitesDataTable({
|
|||||||
allowView = true,
|
allowView = true,
|
||||||
showActions = true,
|
showActions = true,
|
||||||
children,
|
children,
|
||||||
}: WebsitesDataTableProps) {
|
}: {
|
||||||
|
userId?: string;
|
||||||
|
teamId?: string;
|
||||||
|
allowEdit?: boolean;
|
||||||
|
allowView?: boolean;
|
||||||
|
showActions?: boolean;
|
||||||
|
children?: ReactNode;
|
||||||
|
}) {
|
||||||
const queryResult = useWebsites({ userId, teamId });
|
const queryResult = useWebsites({ userId, teamId });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DataTable queryResult={queryResult}>
|
<DataTable queryResult={queryResult}>
|
||||||
{({ data }) => (
|
{({ data }) => (
|
||||||
<WebsitesTable
|
<WebsitesTable
|
||||||
|
teamId={teamId}
|
||||||
data={data}
|
data={data}
|
||||||
showActions={showActions}
|
showActions={showActions}
|
||||||
allowEdit={allowEdit}
|
allowEdit={allowEdit}
|
||||||
|
@ -46,7 +46,7 @@ export function WebsitesTable({
|
|||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
{allowView && (
|
{allowView && (
|
||||||
<Link href={teamId ? `/team/${teamId}/websites/${id}` : `/websites/${id}`}>
|
<Link href={teamId ? `/teams/${teamId}/websites/${id}` : `/websites/${id}`}>
|
||||||
<Button>
|
<Button>
|
||||||
<Icon>
|
<Icon>
|
||||||
<Icons.External />
|
<Icons.External />
|
||||||
|
@ -1,68 +1,63 @@
|
|||||||
|
import { Website } from '@prisma/client';
|
||||||
import {
|
import {
|
||||||
Form,
|
Form,
|
||||||
FormRow,
|
FormRow,
|
||||||
FormButtons,
|
FormButtons,
|
||||||
Flexbox,
|
Flexbox,
|
||||||
TextField,
|
TextField,
|
||||||
SubmitButton,
|
|
||||||
Button,
|
Button,
|
||||||
Toggle,
|
Toggle,
|
||||||
|
LoadingButton,
|
||||||
|
useToasts,
|
||||||
} from 'react-basics';
|
} from 'react-basics';
|
||||||
import { useContext, useEffect, useMemo, useRef, useState } from 'react';
|
import { useContext, useState } from 'react';
|
||||||
import { getRandomChars } from 'next-basics';
|
import { getRandomChars } from 'next-basics';
|
||||||
import { useApi, useMessages } from 'components/hooks';
|
import { useApi, useMessages } from 'components/hooks';
|
||||||
import SettingsContext from '../../SettingsContext';
|
import SettingsContext from 'app/(main)/settings/SettingsContext';
|
||||||
|
|
||||||
const generateId = () => getRandomChars(16);
|
const generateId = () => getRandomChars(16);
|
||||||
|
|
||||||
export function ShareUrl({ websiteId, data, onSave }) {
|
export function ShareUrl({ website, onSave }: { website: Website; onSave?: () => void }) {
|
||||||
const ref = useRef(null);
|
const { domain, shareId } = website;
|
||||||
const { shareUrl } = useContext(SettingsContext);
|
const { hostUrl } = useContext(SettingsContext);
|
||||||
const { formatMessage, labels, messages } = useMessages();
|
const { formatMessage, labels, messages } = useMessages();
|
||||||
const { name, shareId } = data;
|
|
||||||
const [id, setId] = useState(shareId);
|
const [id, setId] = useState(shareId);
|
||||||
|
const { showToast } = useToasts();
|
||||||
const { post, useMutation } = useApi();
|
const { post, useMutation } = useApi();
|
||||||
const { mutate, error } = useMutation({
|
const { mutate, error, isPending } = useMutation({
|
||||||
mutationFn: (data: any) => post(`/websites/${websiteId}`, data),
|
mutationFn: (data: any) => post(`/websites/${website.id}`, data),
|
||||||
});
|
});
|
||||||
const url = useMemo(
|
|
||||||
() => `${shareUrl}${process.env.basePath}/share/${id}/${encodeURIComponent(name)}`,
|
|
||||||
[id, name],
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleSubmit = async (data: any) => {
|
const url = `${hostUrl || location.origin}${
|
||||||
mutate(data, {
|
process.env.basePath
|
||||||
onSuccess: async () => {
|
}/share/${id}/${encodeURIComponent(domain)}`;
|
||||||
onSave(data);
|
|
||||||
ref.current.reset(data);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleGenerate = () => {
|
const handleGenerate = () => {
|
||||||
const id = generateId();
|
setId(generateId());
|
||||||
ref.current.setValue('shareId', id, {
|
|
||||||
shouldValidate: true,
|
|
||||||
shouldDirty: true,
|
|
||||||
});
|
|
||||||
setId(id);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCheck = (checked: boolean) => {
|
const handleCheck = (checked: boolean) => {
|
||||||
const data = { shareId: checked ? generateId() : null };
|
const data = { shareId: checked ? generateId() : null };
|
||||||
mutate(data, {
|
mutate(data, {
|
||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
onSave(data);
|
onSave?.();
|
||||||
|
showToast({ message: formatMessage(messages.saved), variant: 'success' });
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
setId(data.shareId);
|
setId(data.shareId);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
const handleSave = () => {
|
||||||
if (id && id !== shareId) {
|
mutate(
|
||||||
ref.current.setValue('shareId', id);
|
{ shareId: id },
|
||||||
}
|
{
|
||||||
}, [id, shareId]);
|
onSuccess: async () => {
|
||||||
|
showToast({ message: formatMessage(messages.saved), variant: 'success' });
|
||||||
|
onSave?.();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -70,7 +65,7 @@ export function ShareUrl({ websiteId, data, onSave }) {
|
|||||||
{formatMessage(labels.enableShareUrl)}
|
{formatMessage(labels.enableShareUrl)}
|
||||||
</Toggle>
|
</Toggle>
|
||||||
{id && (
|
{id && (
|
||||||
<Form key={websiteId} ref={ref} onSubmit={handleSubmit} error={error} values={data}>
|
<Form error={error}>
|
||||||
<FormRow>
|
<FormRow>
|
||||||
<p>{formatMessage(messages.shareUrl)}</p>
|
<p>{formatMessage(messages.shareUrl)}</p>
|
||||||
<Flexbox gap={10}>
|
<Flexbox gap={10}>
|
||||||
@ -79,7 +74,14 @@ export function ShareUrl({ websiteId, data, onSave }) {
|
|||||||
</Flexbox>
|
</Flexbox>
|
||||||
</FormRow>
|
</FormRow>
|
||||||
<FormButtons>
|
<FormButtons>
|
||||||
<SubmitButton variant="primary">{formatMessage(labels.save)}</SubmitButton>
|
<LoadingButton
|
||||||
|
variant="primary"
|
||||||
|
disabled={id === shareId}
|
||||||
|
isLoading={isPending}
|
||||||
|
onClick={handleSave}
|
||||||
|
>
|
||||||
|
{formatMessage(labels.save)}
|
||||||
|
</LoadingButton>
|
||||||
</FormButtons>
|
</FormButtons>
|
||||||
</Form>
|
</Form>
|
||||||
)}
|
)}
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
import { Button, Modal, ModalTrigger, ActionForm } from 'react-basics';
|
import { Button, Modal, ModalTrigger, ActionForm, useToasts } from 'react-basics';
|
||||||
|
import { useRouter } from 'next/navigation';
|
||||||
|
import { useMessages } from 'components/hooks';
|
||||||
import WebsiteDeleteForm from './WebsiteDeleteForm';
|
import WebsiteDeleteForm from './WebsiteDeleteForm';
|
||||||
import WebsiteResetForm from './WebsiteResetForm';
|
import WebsiteResetForm from './WebsiteResetForm';
|
||||||
import { useMessages } from 'components/hooks';
|
import { touch } from 'store/cache';
|
||||||
|
|
||||||
export function WebsiteData({
|
export function WebsiteData({ websiteId, onSave }: { websiteId: string; onSave?: () => void }) {
|
||||||
websiteId,
|
|
||||||
onSave,
|
|
||||||
}: {
|
|
||||||
websiteId: string;
|
|
||||||
onSave?: (value: string) => void;
|
|
||||||
}) {
|
|
||||||
const { formatMessage, labels, messages } = useMessages();
|
const { formatMessage, labels, messages } = useMessages();
|
||||||
|
const router = useRouter();
|
||||||
|
const { showToast } = useToasts();
|
||||||
|
|
||||||
const handleReset = async () => {
|
const handleReset = async () => {
|
||||||
onSave('reset');
|
showToast({ message: formatMessage(messages.saved), variant: 'success' });
|
||||||
|
onSave?.();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = async () => {
|
const handleDelete = async () => {
|
||||||
onSave('delete');
|
touch('websites');
|
||||||
|
router.push('/settings/websites');
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
import { useApi, useMessages } from 'components/hooks';
|
import { useApi, useMessages } from 'components/hooks';
|
||||||
import { useContext } from 'react';
|
|
||||||
import SettingsContext from '../../SettingsContext';
|
|
||||||
import TypeConfirmationForm from 'components/common/TypeConfirmationForm';
|
import TypeConfirmationForm from 'components/common/TypeConfirmationForm';
|
||||||
|
|
||||||
const CONFIRM_VALUE = 'DELETE';
|
const CONFIRM_VALUE = 'DELETE';
|
||||||
@ -15,10 +13,9 @@ export function WebsiteDeleteForm({
|
|||||||
onClose?: () => void;
|
onClose?: () => void;
|
||||||
}) {
|
}) {
|
||||||
const { formatMessage, labels } = useMessages();
|
const { formatMessage, labels } = useMessages();
|
||||||
const { websitesUrl } = useContext(SettingsContext);
|
|
||||||
const { del, useMutation } = useApi();
|
const { del, useMutation } = useApi();
|
||||||
const { mutate, isPending, error } = useMutation({
|
const { mutate, isPending, error } = useMutation({
|
||||||
mutationFn: (data: any) => del(`${websitesUrl}/${websiteId}`, data),
|
mutationFn: (data: any) => del(`/websites/${websiteId}`, data),
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleConfirm = async () => {
|
const handleConfirm = async () => {
|
||||||
|
@ -1,40 +1,46 @@
|
|||||||
import { SubmitButton, Form, FormInput, FormRow, FormButtons, TextField } from 'react-basics';
|
import { Website } from '@prisma/client';
|
||||||
import { useContext, useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
import { useApi } from 'components/hooks';
|
import {
|
||||||
|
SubmitButton,
|
||||||
|
Form,
|
||||||
|
FormInput,
|
||||||
|
FormRow,
|
||||||
|
FormButtons,
|
||||||
|
TextField,
|
||||||
|
useToasts,
|
||||||
|
} from 'react-basics';
|
||||||
|
import { useApi, useMessages } from 'components/hooks';
|
||||||
import { DOMAIN_REGEX } from 'lib/constants';
|
import { DOMAIN_REGEX } from 'lib/constants';
|
||||||
import { useMessages } from 'components/hooks';
|
|
||||||
import SettingsContext from '../../SettingsContext';
|
|
||||||
|
|
||||||
export function WebsiteEditForm({
|
export function WebsiteEditForm({
|
||||||
websiteId,
|
website,
|
||||||
data,
|
|
||||||
onSave,
|
onSave,
|
||||||
}: {
|
}: {
|
||||||
websiteId: string;
|
website: Website;
|
||||||
data: any[];
|
|
||||||
onSave?: (data: any) => void;
|
onSave?: (data: any) => void;
|
||||||
}) {
|
}) {
|
||||||
const { formatMessage, labels, messages } = useMessages();
|
const { formatMessage, labels, messages } = useMessages();
|
||||||
const { websitesUrl } = useContext(SettingsContext);
|
|
||||||
const { post, useMutation } = useApi();
|
const { post, useMutation } = useApi();
|
||||||
const { mutate, error } = useMutation({
|
const { mutate, error } = useMutation({
|
||||||
mutationFn: (data: any) => post(`${websitesUrl}/${websiteId}`, data),
|
mutationFn: (data: any) => post(`/websites/${website.id}`, data),
|
||||||
});
|
});
|
||||||
const ref = useRef(null);
|
const ref = useRef(null);
|
||||||
|
const { showToast } = useToasts();
|
||||||
|
|
||||||
const handleSubmit = async (data: any) => {
|
const handleSubmit = async (data: any) => {
|
||||||
mutate(data, {
|
mutate(data, {
|
||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
|
showToast({ message: formatMessage(messages.saved), variant: 'success' });
|
||||||
ref.current.reset(data);
|
ref.current.reset(data);
|
||||||
onSave(data);
|
onSave?.(data);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form ref={ref} onSubmit={handleSubmit} error={error} values={data}>
|
<Form ref={ref} onSubmit={handleSubmit} error={error} values={website}>
|
||||||
<FormRow label={formatMessage(labels.websiteId)}>
|
<FormRow label={formatMessage(labels.websiteId)}>
|
||||||
<TextField value={websiteId} readOnly allowCopy />
|
<TextField value={website.id} readOnly allowCopy />
|
||||||
</FormRow>
|
</FormRow>
|
||||||
<FormRow label={formatMessage(labels.name)}>
|
<FormRow label={formatMessage(labels.name)}>
|
||||||
<FormInput name="name" rules={{ required: formatMessage(labels.required) }}>
|
<FormInput name="name" rules={{ required: formatMessage(labels.required) }}>
|
||||||
|
5
src/app/(main)/teams/[id]/websites/[websiteId]/page.tsx
Normal file
5
src/app/(main)/teams/[id]/websites/[websiteId]/page.tsx
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import WebsiteDetails from 'app/(main)/websites/[id]/WebsiteDetails';
|
||||||
|
|
||||||
|
export default function TeamWebsitePage({ params: { websiteId } }) {
|
||||||
|
return <WebsiteDetails websiteId={websiteId} />;
|
||||||
|
}
|
6
src/app/(main)/websites/[id]/WebsiteContext.tsx
Normal file
6
src/app/(main)/websites/[id]/WebsiteContext.tsx
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
'use client';
|
||||||
|
import { createContext } from 'react';
|
||||||
|
|
||||||
|
export const WebsiteContext = createContext(null);
|
||||||
|
|
||||||
|
export default WebsiteContext;
|
@ -27,6 +27,11 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
color: var(--base700);
|
||||||
|
margin-right: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
.actions {
|
.actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
@ -1,16 +1,26 @@
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import React, { ReactNode } from 'react';
|
import React, { ReactNode } from 'react';
|
||||||
|
import { Icon } from 'react-basics';
|
||||||
import styles from './PageHeader.module.css';
|
import styles from './PageHeader.module.css';
|
||||||
|
|
||||||
export interface PageHeaderProps {
|
export function PageHeader({
|
||||||
|
title,
|
||||||
|
icon,
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
title?: ReactNode;
|
title?: ReactNode;
|
||||||
|
icon?: ReactNode;
|
||||||
className?: string;
|
className?: string;
|
||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
}
|
}) {
|
||||||
|
|
||||||
export function PageHeader({ title, className, children }: PageHeaderProps) {
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames(styles.header, className)}>
|
<div className={classNames(styles.header, className)}>
|
||||||
|
{icon && (
|
||||||
|
<Icon size="lg" className={styles.icon}>
|
||||||
|
{icon}
|
||||||
|
</Icon>
|
||||||
|
)}
|
||||||
{title && <div className={styles.title}>{title}</div>}
|
{title && <div className={styles.title}>{title}</div>}
|
||||||
<div className={styles.actions}>{children}</div>
|
<div className={styles.actions}>{children}</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user