mirror of
https://github.com/umami-software/umami.git
synced 2026-02-09 23:27:12 +01:00
Zen components conversion.
This commit is contained in:
parent
aac1a12e51
commit
5999bf6256
142 changed files with 1235 additions and 1454 deletions
|
|
@ -3,11 +3,10 @@ import {
|
|||
Button,
|
||||
Form,
|
||||
FormButtons,
|
||||
FormInput,
|
||||
FormRow,
|
||||
SubmitButton,
|
||||
FormField,
|
||||
FormSubmitButton,
|
||||
TextField,
|
||||
} from 'react-basics';
|
||||
} from '@umami/react-zen';
|
||||
|
||||
export function TeamAddForm({ onSave, onClose }: { onSave: () => void; onClose: () => void }) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
|
|
@ -27,16 +26,14 @@ export function TeamAddForm({ onSave, onClose }: { onSave: () => void; onClose:
|
|||
|
||||
return (
|
||||
<Form onSubmit={handleSubmit} error={error}>
|
||||
<FormRow label={formatMessage(labels.name)}>
|
||||
<FormInput name="name" rules={{ required: formatMessage(labels.required) }}>
|
||||
<TextField autoComplete="off" />
|
||||
</FormInput>
|
||||
</FormRow>
|
||||
<FormButtons flex>
|
||||
<SubmitButton variant="primary" disabled={isPending}>
|
||||
<FormField name="name" label={formatMessage(labels.name)}>
|
||||
<TextField autoComplete="off" />
|
||||
</FormField>
|
||||
<FormButtons>
|
||||
<FormSubmitButton variant="primary" disabled={isPending}>
|
||||
{formatMessage(labels.save)}
|
||||
</SubmitButton>
|
||||
<Button disabled={isPending} onClick={onClose}>
|
||||
</FormSubmitButton>
|
||||
<Button isDisabled={isPending} onPress={onClose}>
|
||||
{formatMessage(labels.cancel)}
|
||||
</Button>
|
||||
</FormButtons>
|
||||
|
|
|
|||
|
|
@ -1,20 +1,17 @@
|
|||
import { useRef } from 'react';
|
||||
import {
|
||||
Form,
|
||||
FormRow,
|
||||
FormInput,
|
||||
FormField,
|
||||
FormButtons,
|
||||
TextField,
|
||||
Button,
|
||||
SubmitButton,
|
||||
} from 'react-basics';
|
||||
FormSubmitButton,
|
||||
} from '@umami/react-zen';
|
||||
import { useApi, useMessages, useModified } 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 ref = useRef(null);
|
||||
const { touch } = useModified();
|
||||
|
||||
const handleSubmit = async (data: any) => {
|
||||
|
|
@ -28,15 +25,17 @@ export function TeamJoinForm({ onSave, onClose }: { onSave: () => void; onClose:
|
|||
};
|
||||
|
||||
return (
|
||||
<Form ref={ref} onSubmit={handleSubmit} error={error}>
|
||||
<FormRow label={formatMessage(labels.accessCode)}>
|
||||
<FormInput name="accessCode" rules={{ required: formatMessage(labels.required) }}>
|
||||
<TextField autoComplete="off" />
|
||||
</FormInput>
|
||||
</FormRow>
|
||||
<FormButtons flex>
|
||||
<SubmitButton variant="primary">{formatMessage(labels.join)}</SubmitButton>
|
||||
<Button onClick={onClose}>{formatMessage(labels.cancel)}</Button>
|
||||
<Form onSubmit={handleSubmit} error={error}>
|
||||
<FormField
|
||||
label={formatMessage(labels.accessCode)}
|
||||
name="accessCode"
|
||||
rules={{ required: formatMessage(labels.required) }}
|
||||
>
|
||||
<TextField autoComplete="off" />
|
||||
</FormField>
|
||||
<FormButtons>
|
||||
<FormSubmitButton variant="primary">{formatMessage(labels.join)}</FormSubmitButton>
|
||||
<Button onPress={onClose}>{formatMessage(labels.cancel)}</Button>
|
||||
</FormButtons>
|
||||
</Form>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useLocale, useLogin, useMessages, useModified } from '@/components/hooks';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { Button, Icon, Icons, Modal, ModalTrigger, Text } from 'react-basics';
|
||||
import { Button, Icon, Icons, Modal, DialogTrigger, Dialog, Text } from '@umami/react-zen';
|
||||
import { TeamLeaveForm } from './TeamLeaveForm';
|
||||
|
||||
export function TeamLeaveButton({ teamId, teamName }: { teamId: string; teamName: string }) {
|
||||
|
|
@ -16,24 +16,26 @@ export function TeamLeaveButton({ teamId, teamName }: { teamId: string; teamName
|
|||
};
|
||||
|
||||
return (
|
||||
<ModalTrigger>
|
||||
<DialogTrigger>
|
||||
<Button variant="secondary">
|
||||
<Icon rotate={dir === 'rtl' ? 180 : 0}>
|
||||
<Icons.Logout />
|
||||
</Icon>
|
||||
<Text>{formatMessage(labels.leave)}</Text>
|
||||
</Button>
|
||||
<Modal title={formatMessage(labels.leaveTeam)}>
|
||||
{(close: () => void) => (
|
||||
<TeamLeaveForm
|
||||
teamId={teamId}
|
||||
userId={user.id}
|
||||
teamName={teamName}
|
||||
onSave={handleLeave}
|
||||
onClose={close}
|
||||
/>
|
||||
)}
|
||||
<Modal>
|
||||
<Dialog title={formatMessage(labels.leaveTeam)}>
|
||||
{({ close }) => (
|
||||
<TeamLeaveForm
|
||||
teamId={teamId}
|
||||
userId={user.id}
|
||||
teamName={teamName}
|
||||
onSave={handleLeave}
|
||||
onClose={close}
|
||||
/>
|
||||
)}
|
||||
</Dialog>
|
||||
</Modal>
|
||||
</ModalTrigger>
|
||||
</DialogTrigger>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Button, Icon, Modal, ModalTrigger, Text, useToasts } from 'react-basics';
|
||||
import { Button, Icon, Modal, DialogTrigger, Dialog, Text, useToast } from '@umami/react-zen';
|
||||
import { Icons } from '@/components/icons';
|
||||
import { useMessages, useModified } from '@/components/hooks';
|
||||
import { TeamAddForm } from './TeamAddForm';
|
||||
|
|
@ -6,26 +6,28 @@ import { messages } from '@/components/messages';
|
|||
|
||||
export function TeamsAddButton({ onSave }: { onSave?: () => void }) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const { showToast } = useToasts();
|
||||
const { toast } = useToast();
|
||||
const { touch } = useModified();
|
||||
|
||||
const handleSave = async () => {
|
||||
showToast({ message: formatMessage(messages.saved), variant: 'success' });
|
||||
toast(formatMessage(messages.saved));
|
||||
touch('teams');
|
||||
onSave?.();
|
||||
};
|
||||
|
||||
return (
|
||||
<ModalTrigger>
|
||||
<DialogTrigger>
|
||||
<Button variant="primary">
|
||||
<Icon>
|
||||
<Icons.Plus />
|
||||
</Icon>
|
||||
<Text>{formatMessage(labels.createTeam)}</Text>
|
||||
</Button>
|
||||
<Modal title={formatMessage(labels.createTeam)}>
|
||||
{(close: () => void) => <TeamAddForm onSave={handleSave} onClose={close} />}
|
||||
<Modal>
|
||||
<Dialog title={formatMessage(labels.createTeam)}>
|
||||
{({ close }) => <TeamAddForm onSave={handleSave} onClose={close} />}
|
||||
</Dialog>
|
||||
</Modal>
|
||||
</ModalTrigger>
|
||||
</DialogTrigger>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Flexbox } from 'react-basics';
|
||||
import { Row } from '@umami/react-zen';
|
||||
import { PageHeader } from '@/components/layout/PageHeader';
|
||||
import { ROLES } from '@/lib/constants';
|
||||
import { useLogin, useMessages } from '@/components/hooks';
|
||||
|
|
@ -12,10 +12,10 @@ export function TeamsHeader({ allowCreate = true }: { allowCreate?: boolean }) {
|
|||
|
||||
return (
|
||||
<PageHeader title={formatMessage(labels.teams)}>
|
||||
<Flexbox gap={10}>
|
||||
<Row gap="3">
|
||||
{!cloudMode && <TeamsJoinButton />}
|
||||
{allowCreate && user.role !== ROLES.viewOnly && <TeamsAddButton />}
|
||||
</Flexbox>
|
||||
</Row>
|
||||
</PageHeader>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,29 +1,31 @@
|
|||
import { Button, Icon, Modal, ModalTrigger, Text, useToasts } from 'react-basics';
|
||||
import { Button, Icon, Modal, DialogTrigger, Dialog, Text, useToast } from '@umami/react-zen';
|
||||
import { Icons } from '@/components/icons';
|
||||
import { useMessages, useModified } from '@/components/hooks';
|
||||
import { TeamJoinForm } from './TeamJoinForm';
|
||||
|
||||
export function TeamsJoinButton() {
|
||||
const { formatMessage, labels, messages } = useMessages();
|
||||
const { showToast } = useToasts();
|
||||
const { toast } = useToast();
|
||||
const { touch } = useModified();
|
||||
|
||||
const handleJoin = () => {
|
||||
showToast({ message: formatMessage(messages.saved), variant: 'success' });
|
||||
toast(formatMessage(messages.saved));
|
||||
touch('teams');
|
||||
};
|
||||
|
||||
return (
|
||||
<ModalTrigger>
|
||||
<DialogTrigger>
|
||||
<Button variant="secondary">
|
||||
<Icon>
|
||||
<Icons.AddUser />
|
||||
</Icon>
|
||||
<Text>{formatMessage(labels.joinTeam)}</Text>
|
||||
</Button>
|
||||
<Modal title={formatMessage(labels.joinTeam)}>
|
||||
{close => <TeamJoinForm onSave={handleJoin} onClose={close} />}
|
||||
<Modal>
|
||||
<Dialog title={formatMessage(labels.joinTeam)}>
|
||||
{({ close }) => <TeamJoinForm onSave={handleJoin} onClose={close} />}
|
||||
</Dialog>
|
||||
</Modal>
|
||||
</ModalTrigger>
|
||||
</DialogTrigger>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { GridColumn, GridTable, Icon, Text } from 'react-basics';
|
||||
import { DataColumn, DataTable, Icon, Text } from '@umami/react-zen';
|
||||
import { useMessages } from '@/components/hooks';
|
||||
import { Icons } from '@/components/icons';
|
||||
import { ROLES } from '@/lib/constants';
|
||||
|
|
@ -15,33 +15,33 @@ export function TeamsTable({
|
|||
const { formatMessage, labels } = useMessages();
|
||||
|
||||
return (
|
||||
<GridTable data={data}>
|
||||
<GridColumn name="name" label={formatMessage(labels.name)} />
|
||||
<GridColumn name="owner" label={formatMessage(labels.owner)}>
|
||||
{row => row.teamUser.find(({ role }) => role === ROLES.teamOwner)?.user?.username}
|
||||
</GridColumn>
|
||||
<GridColumn name="websites" label={formatMessage(labels.websites)}>
|
||||
{row => row._count.website}
|
||||
</GridColumn>
|
||||
<GridColumn name="members" label={formatMessage(labels.members)}>
|
||||
{row => row._count.teamUser}
|
||||
</GridColumn>
|
||||
<DataTable data={data}>
|
||||
<DataColumn id="name" label={formatMessage(labels.name)} />
|
||||
<DataColumn id="owner" label={formatMessage(labels.owner)}>
|
||||
{(row: any) => row.teamUser.find(({ role }) => role === ROLES.teamOwner)?.user?.username}
|
||||
</DataColumn>
|
||||
<DataColumn id="websites" label={formatMessage(labels.websites)}>
|
||||
{(row: any) => row._count.website}
|
||||
</DataColumn>
|
||||
<DataColumn id="members" label={formatMessage(labels.members)}>
|
||||
{(row: any) => row._count.teamUser}
|
||||
</DataColumn>
|
||||
{showActions && (
|
||||
<GridColumn name="action" label=" " alignment="end">
|
||||
{row => {
|
||||
<DataColumn id="action" label=" " align="end">
|
||||
{(row: any) => {
|
||||
const { id } = row;
|
||||
|
||||
return (
|
||||
<LinkButton href={`/teams/${id}/settings`}>
|
||||
<Icon>
|
||||
<Icons.ArrowRight />
|
||||
<Icons.Arrow />
|
||||
</Icon>
|
||||
<Text>{formatMessage(labels.view)}</Text>
|
||||
</LinkButton>
|
||||
);
|
||||
}}
|
||||
</GridColumn>
|
||||
</DataColumn>
|
||||
)}
|
||||
</GridTable>
|
||||
</DataTable>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Button, Icon, Icons, Text } from 'react-basics';
|
||||
import { Button, Icon, Icons, Text } from '@umami/react-zen';
|
||||
import styles from './WebsiteTags.module.css';
|
||||
|
||||
export function WebsiteTags({
|
||||
|
|
@ -21,7 +21,7 @@ export function WebsiteTags({
|
|||
|
||||
return (
|
||||
<div key={websiteId} className={styles.tag}>
|
||||
<Button onClick={() => onClick(websiteId)} variant="primary" size="sm">
|
||||
<Button onPress={() => onClick(websiteId)} variant="primary" size="sm">
|
||||
<Text>
|
||||
<b>{`${website.name}`}</b>
|
||||
</Text>
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
import {
|
||||
Dropdown,
|
||||
Item,
|
||||
Select,
|
||||
ListItem,
|
||||
Form,
|
||||
FormRow,
|
||||
FormField,
|
||||
FormButtons,
|
||||
FormInput,
|
||||
FormSubmitButton,
|
||||
TextField,
|
||||
PasswordField,
|
||||
SubmitButton,
|
||||
Button,
|
||||
} from 'react-basics';
|
||||
} from '@umami/react-zen';
|
||||
import { useApi, useMessages } from '@/components/hooks';
|
||||
import { ROLES } from '@/lib/constants';
|
||||
|
||||
|
|
@ -29,44 +28,38 @@ export function UserAddForm({ onSave, onClose }) {
|
|||
});
|
||||
};
|
||||
|
||||
const renderValue = (value: string) => {
|
||||
if (value === ROLES.user) {
|
||||
return formatMessage(labels.user);
|
||||
}
|
||||
if (value === ROLES.admin) {
|
||||
return formatMessage(labels.admin);
|
||||
}
|
||||
if (value === ROLES.viewOnly) {
|
||||
return formatMessage(labels.viewOnly);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Form onSubmit={handleSubmit} error={error}>
|
||||
<FormRow label={formatMessage(labels.username)}>
|
||||
<FormInput name="username" rules={{ required: formatMessage(labels.required) }}>
|
||||
<TextField autoComplete="new-username" />
|
||||
</FormInput>
|
||||
</FormRow>
|
||||
<FormRow label={formatMessage(labels.password)}>
|
||||
<FormInput name="password" rules={{ required: formatMessage(labels.required) }}>
|
||||
<PasswordField autoComplete="new-password" />
|
||||
</FormInput>
|
||||
</FormRow>
|
||||
<FormRow label={formatMessage(labels.role)}>
|
||||
<FormInput name="role" rules={{ required: formatMessage(labels.required) }}>
|
||||
<Dropdown renderValue={renderValue}>
|
||||
<Item key={ROLES.viewOnly}>{formatMessage(labels.viewOnly)}</Item>
|
||||
<Item key={ROLES.user}>{formatMessage(labels.user)}</Item>
|
||||
<Item key={ROLES.admin}>{formatMessage(labels.admin)}</Item>
|
||||
</Dropdown>
|
||||
</FormInput>
|
||||
</FormRow>
|
||||
<FormButtons flex>
|
||||
<SubmitButton variant="primary" disabled={false}>
|
||||
<FormField
|
||||
label={formatMessage(labels.username)}
|
||||
name="username"
|
||||
rules={{ required: formatMessage(labels.required) }}
|
||||
>
|
||||
<TextField autoComplete="new-username" />
|
||||
</FormField>
|
||||
<FormField
|
||||
label={formatMessage(labels.password)}
|
||||
name="password"
|
||||
rules={{ required: formatMessage(labels.required) }}
|
||||
>
|
||||
<PasswordField autoComplete="new-password" />
|
||||
</FormField>
|
||||
<FormField
|
||||
label={formatMessage(labels.role)}
|
||||
name="role"
|
||||
rules={{ required: formatMessage(labels.required) }}
|
||||
>
|
||||
<Select>
|
||||
<ListItem id={ROLES.viewOnly}>{formatMessage(labels.viewOnly)}</ListItem>
|
||||
<ListItem id={ROLES.user}>{formatMessage(labels.user)}</ListItem>
|
||||
<ListItem id={ROLES.admin}>{formatMessage(labels.admin)}</ListItem>
|
||||
</Select>
|
||||
</FormField>
|
||||
<FormButtons>
|
||||
<FormSubmitButton variant="primary" disabled={false}>
|
||||
{formatMessage(labels.save)}
|
||||
</SubmitButton>
|
||||
<Button disabled={isPending} onClick={onClose}>
|
||||
</FormSubmitButton>
|
||||
<Button isDisabled={isPending} onPress={onClose}>
|
||||
{formatMessage(labels.cancel)}
|
||||
</Button>
|
||||
</FormButtons>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
import {
|
||||
Form,
|
||||
FormRow,
|
||||
FormField,
|
||||
FormButtons,
|
||||
Flexbox,
|
||||
TextField,
|
||||
Button,
|
||||
Toggle,
|
||||
LoadingButton,
|
||||
} from 'react-basics';
|
||||
Switch,
|
||||
FormSubmitButton,
|
||||
Box,
|
||||
useToast,
|
||||
} from '@umami/react-zen';
|
||||
import { useContext, useState } from 'react';
|
||||
import { getRandomChars } from '@/lib/crypto';
|
||||
import { useApi, useMessages, useModified } from '@/components/hooks';
|
||||
|
|
@ -25,6 +26,7 @@ export function ShareUrl({ hostUrl, onSave }: { hostUrl?: string; onSave?: () =>
|
|||
mutationFn: (data: any) => post(`/websites/${website.id}`, data),
|
||||
});
|
||||
const { touch } = useModified();
|
||||
const { toast } = useToast();
|
||||
|
||||
const url = `${hostUrl || window?.location.origin || ''}${
|
||||
process.env.basePath || ''
|
||||
|
|
@ -34,7 +36,8 @@ export function ShareUrl({ hostUrl, onSave }: { hostUrl?: string; onSave?: () =>
|
|||
setId(generateId());
|
||||
};
|
||||
|
||||
const handleCheck = (checked: boolean) => {
|
||||
const handleSwitch = (checked: boolean) => {
|
||||
console.log({ checked });
|
||||
const data = {
|
||||
name: website.name,
|
||||
domain: website.domain,
|
||||
|
|
@ -42,6 +45,7 @@ export function ShareUrl({ hostUrl, onSave }: { hostUrl?: string; onSave?: () =>
|
|||
};
|
||||
mutate(data, {
|
||||
onSuccess: async () => {
|
||||
toast(formatMessage(messages.saved));
|
||||
touch(`website:${website.id}`);
|
||||
onSave?.();
|
||||
},
|
||||
|
|
@ -54,6 +58,7 @@ export function ShareUrl({ hostUrl, onSave }: { hostUrl?: string; onSave?: () =>
|
|||
{ name: website.name, domain: website.domain, shareId: id },
|
||||
{
|
||||
onSuccess: async () => {
|
||||
toast(formatMessage(messages.saved));
|
||||
touch(`website:${website.id}`);
|
||||
onSave?.();
|
||||
},
|
||||
|
|
@ -63,27 +68,21 @@ export function ShareUrl({ hostUrl, onSave }: { hostUrl?: string; onSave?: () =>
|
|||
|
||||
return (
|
||||
<>
|
||||
<Toggle checked={Boolean(id)} onChecked={handleCheck} style={{ marginBottom: 30 }}>
|
||||
{formatMessage(labels.enableShareUrl)}
|
||||
</Toggle>
|
||||
<Box marginBottom="6">
|
||||
<Switch defaultSelected={!!id} isSelected={!!id} onChange={handleSwitch}>
|
||||
{formatMessage(labels.enableShareUrl)}
|
||||
</Switch>
|
||||
</Box>
|
||||
{id && (
|
||||
<Form error={error}>
|
||||
<FormRow>
|
||||
<p>{formatMessage(messages.shareUrl)}</p>
|
||||
<Flexbox gap={10}>
|
||||
<TextField value={url} readOnly allowCopy />
|
||||
<Button onClick={handleGenerate}>{formatMessage(labels.regenerate)}</Button>
|
||||
</Flexbox>
|
||||
</FormRow>
|
||||
<FormButtons>
|
||||
<LoadingButton
|
||||
variant="primary"
|
||||
disabled={id === shareId}
|
||||
isLoading={isPending}
|
||||
onClick={handleSave}
|
||||
>
|
||||
<Form onSubmit={handleSave} error={error} values={{ id, url }}>
|
||||
<FormField label={formatMessage(messages.shareUrl)} name="url">
|
||||
<TextField isReadOnly allowCopy />
|
||||
</FormField>
|
||||
<FormButtons justifyContent="space-between">
|
||||
<Button onPress={handleGenerate}>{formatMessage(labels.regenerate)}</Button>
|
||||
<FormSubmitButton variant="primary" isDisabled={id === shareId} isLoading={isPending}>
|
||||
{formatMessage(labels.save)}
|
||||
</LoadingButton>
|
||||
</FormSubmitButton>
|
||||
</FormButtons>
|
||||
</Form>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { TextArea } from 'react-basics';
|
||||
import { TextArea } from '@umami/react-zen';
|
||||
import { useMessages, useConfig } from '@/components/hooks';
|
||||
|
||||
const SCRIPT_NAME = 'script.js';
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import { Button, Modal, ModalTrigger, ActionForm } from 'react-basics';
|
||||
import { Button, Modal, DialogTrigger, Dialog, Column } from '@umami/react-zen';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useLogin, useMessages, useModified, useTeams, useTeamUrl } from '@/components/hooks';
|
||||
import { WebsiteDeleteForm } from './WebsiteDeleteForm';
|
||||
import { WebsiteResetForm } from './WebsiteResetForm';
|
||||
import { WebsiteTransferForm } from './WebsiteTransferForm';
|
||||
import { ActionForm } from '@/components/layout/ActionForm';
|
||||
import { ROLES } from '@/lib/constants';
|
||||
|
||||
export function WebsiteData({ websiteId, onSave }: { websiteId: string; onSave?: () => void }) {
|
||||
|
|
@ -39,50 +40,58 @@ export function WebsiteData({ websiteId, onSave }: { websiteId: string; onSave?:
|
|||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Column gap="6">
|
||||
<ActionForm
|
||||
label={formatMessage(labels.transferWebsite)}
|
||||
description={formatMessage(messages.transferWebsite)}
|
||||
>
|
||||
<ModalTrigger disabled={!canTransferWebsite}>
|
||||
<Button variant="secondary" disabled={!canTransferWebsite}>
|
||||
<DialogTrigger>
|
||||
<Button variant="secondary" isDisabled={!canTransferWebsite}>
|
||||
{formatMessage(labels.transfer)}
|
||||
</Button>
|
||||
<Modal title={formatMessage(labels.transferWebsite)}>
|
||||
{(close: () => void) => (
|
||||
<WebsiteTransferForm websiteId={websiteId} onSave={handleSave} onClose={close} />
|
||||
)}
|
||||
<Modal>
|
||||
<Dialog title={formatMessage(labels.transferWebsite)}>
|
||||
{({ close }) => (
|
||||
<WebsiteTransferForm websiteId={websiteId} onSave={handleSave} onClose={close} />
|
||||
)}
|
||||
</Dialog>
|
||||
</Modal>
|
||||
</ModalTrigger>
|
||||
</DialogTrigger>
|
||||
</ActionForm>
|
||||
|
||||
<ActionForm
|
||||
label={formatMessage(labels.resetWebsite)}
|
||||
description={formatMessage(messages.resetWebsiteWarning)}
|
||||
>
|
||||
<ModalTrigger>
|
||||
<DialogTrigger>
|
||||
<Button variant="secondary">{formatMessage(labels.reset)}</Button>
|
||||
<Modal title={formatMessage(labels.resetWebsite)}>
|
||||
{(close: () => void) => (
|
||||
<WebsiteResetForm websiteId={websiteId} onSave={handleReset} onClose={close} />
|
||||
)}
|
||||
<Modal>
|
||||
<Dialog title={formatMessage(labels.resetWebsite)}>
|
||||
{({ close }) => (
|
||||
<WebsiteResetForm websiteId={websiteId} onSave={handleReset} onClose={close} />
|
||||
)}
|
||||
</Dialog>
|
||||
</Modal>
|
||||
</ModalTrigger>
|
||||
</DialogTrigger>
|
||||
</ActionForm>
|
||||
|
||||
<ActionForm
|
||||
label={formatMessage(labels.deleteWebsite)}
|
||||
description={formatMessage(messages.deleteWebsiteWarning)}
|
||||
>
|
||||
<ModalTrigger>
|
||||
<DialogTrigger>
|
||||
<Button data-test="button-delete" variant="danger">
|
||||
{formatMessage(labels.delete)}
|
||||
</Button>
|
||||
<Modal title={formatMessage(labels.deleteWebsite)}>
|
||||
{(close: () => void) => (
|
||||
<WebsiteDeleteForm websiteId={websiteId} onSave={handleSave} onClose={close} />
|
||||
)}
|
||||
<Modal>
|
||||
<Dialog title={formatMessage(labels.deleteWebsite)}>
|
||||
{({ close }) => (
|
||||
<WebsiteDeleteForm websiteId={websiteId} onSave={handleSave} onClose={close} />
|
||||
)}
|
||||
</Dialog>
|
||||
</Modal>
|
||||
</ModalTrigger>
|
||||
</DialogTrigger>
|
||||
</ActionForm>
|
||||
</>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ export function WebsiteSettings({
|
|||
<Link href={`/websites/${websiteId}`} target={openExternal ? '_blank' : null}>
|
||||
<Button variant="primary">
|
||||
<Icon>
|
||||
<Icons.ArrowRight />
|
||||
<Icons.Arrow />
|
||||
</Icon>
|
||||
<Text>{formatMessage(labels.view)}</Text>
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -3,13 +3,13 @@ import {
|
|||
Button,
|
||||
Form,
|
||||
FormButtons,
|
||||
FormRow,
|
||||
LoadingButton,
|
||||
FormField,
|
||||
FormSubmitButton,
|
||||
Loading,
|
||||
Dropdown,
|
||||
Item,
|
||||
Flexbox,
|
||||
} from 'react-basics';
|
||||
Select,
|
||||
ListItem,
|
||||
Text,
|
||||
} from '@umami/react-zen';
|
||||
import { useApi, useLogin, useMessages, useTeams } from '@/components/hooks';
|
||||
import { WebsiteContext } from '@/app/(main)/websites/[websiteId]/WebsiteProvider';
|
||||
import { ROLES } from '@/lib/constants';
|
||||
|
|
@ -28,12 +28,19 @@ export function WebsiteTransferForm({
|
|||
const [teamId, setTeamId] = useState<string>(null);
|
||||
const { formatMessage, labels, messages } = useMessages();
|
||||
const { post, useMutation } = useApi();
|
||||
const { mutate, isPending, error } = useMutation({
|
||||
const { mutate, error } = useMutation({
|
||||
mutationFn: (data: any) => post(`/websites/${websiteId}/transfer`, data),
|
||||
});
|
||||
const { result, query } = useTeams(user.id);
|
||||
const isTeamWebsite = !!website?.teamId;
|
||||
|
||||
const items = result.data.filter(({ teamUser }) =>
|
||||
teamUser.find(
|
||||
({ role, userId }) =>
|
||||
[ROLES.teamOwner, ROLES.teamManager].includes(role) && userId === user.id,
|
||||
),
|
||||
);
|
||||
|
||||
const handleSubmit = async () => {
|
||||
mutate(
|
||||
{
|
||||
|
|
@ -53,45 +60,35 @@ export function WebsiteTransferForm({
|
|||
setTeamId(key as string);
|
||||
};
|
||||
|
||||
const renderValue = (teamId: string) => result?.data?.find(({ id }) => id === teamId)?.name;
|
||||
|
||||
if (query.isLoading) {
|
||||
return <Loading icon="dots" position="center" />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Form error={error}>
|
||||
<FormRow>
|
||||
<Flexbox direction="column" gap={20}>
|
||||
{formatMessage(
|
||||
isTeamWebsite ? messages.transferTeamWebsiteToUser : messages.transferUserWebsiteToTeam,
|
||||
)}
|
||||
{!isTeamWebsite && (
|
||||
<Dropdown onChange={handleChange} value={teamId} renderValue={renderValue}>
|
||||
{result.data
|
||||
.filter(({ teamUser }) =>
|
||||
teamUser.find(
|
||||
({ role, userId }) =>
|
||||
[ROLES.teamOwner, ROLES.teamManager].includes(role) && userId === user.id,
|
||||
),
|
||||
)
|
||||
.map(({ id, name }) => {
|
||||
return <Item key={id}>{name}</Item>;
|
||||
})}
|
||||
</Dropdown>
|
||||
)}
|
||||
</Flexbox>
|
||||
</FormRow>
|
||||
<FormButtons flex>
|
||||
<LoadingButton
|
||||
variant="primary"
|
||||
isLoading={isPending}
|
||||
disabled={!isTeamWebsite && !teamId}
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
<Form onSubmit={handleSubmit} error={error} values={{ teamId }}>
|
||||
<Text>
|
||||
{formatMessage(
|
||||
isTeamWebsite ? messages.transferTeamWebsiteToUser : messages.transferUserWebsiteToTeam,
|
||||
)}
|
||||
</Text>
|
||||
<FormField name="teamId">
|
||||
{!isTeamWebsite && (
|
||||
<Select onSelectionChange={handleChange} value={teamId}>
|
||||
{items.map(({ id, name }) => {
|
||||
return (
|
||||
<ListItem key={id} id={id}>
|
||||
{name}
|
||||
</ListItem>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
)}
|
||||
</FormField>
|
||||
<FormButtons>
|
||||
<Button onPress={onClose}>{formatMessage(labels.cancel)}</Button>
|
||||
<FormSubmitButton variant="primary" isDisabled={!isTeamWebsite && !teamId}>
|
||||
{formatMessage(labels.transfer)}
|
||||
</LoadingButton>
|
||||
<Button onClick={onClose}>{formatMessage(labels.cancel)}</Button>
|
||||
</FormSubmitButton>
|
||||
</FormButtons>
|
||||
</Form>
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue