mirror of
https://github.com/umami-software/umami.git
synced 2025-12-08 05:12:36 +01:00
feat: add invitation and join team features
This commit is contained in:
parent
60eaaaff60
commit
c61188d524
8 changed files with 110 additions and 0 deletions
22
src/app/(main)/invite/InviteForm.module.css
Normal file
22
src/app/(main)/invite/InviteForm.module.css
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
.container {
|
||||
margin: 0 auto;
|
||||
max-width: 400px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.form {
|
||||
background: var(--base50);
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.container {
|
||||
margin: 0;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.form {
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
||||
55
src/app/(main)/invite/InviteForm.tsx
Normal file
55
src/app/(main)/invite/InviteForm.tsx
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
'use client';
|
||||
import { Form, FormRow, FormInput, FormButtons, TextField, Button } from 'react-basics';
|
||||
import { useApi, useMessages, useModified } from '@/components/hooks';
|
||||
import styles from './InviteForm.module.css';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
|
||||
export function InviteForm() {
|
||||
const searchParams = useSearchParams();
|
||||
|
||||
const accessCode = searchParams.get('accessCode');
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const { post, useMutation } = useApi();
|
||||
|
||||
const { mutate, error } = useMutation({
|
||||
mutationFn: (data: any) => post('/teams/join', data),
|
||||
});
|
||||
|
||||
const { touch } = useModified();
|
||||
|
||||
const handleSubmit = async (data: any) => {
|
||||
mutate(data, {
|
||||
onSuccess: async () => {
|
||||
touch('teams:members');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.form}>
|
||||
<Form
|
||||
onSubmit={handleSubmit}
|
||||
error={error}
|
||||
values={{
|
||||
accessCode: accessCode || '',
|
||||
}}
|
||||
autoComplete="off"
|
||||
preventSubmit={false}
|
||||
>
|
||||
<FormRow label={formatMessage(labels.accessCode)}>
|
||||
<FormInput name="accessCode" rules={{ required: formatMessage(labels.required) }}>
|
||||
<TextField autoComplete="off" />
|
||||
</FormInput>
|
||||
</FormRow>
|
||||
<FormButtons flex>
|
||||
<Button type="submit" variant="primary">
|
||||
{formatMessage(labels.join)}
|
||||
</Button>
|
||||
<Button onClick={() => {}}>{formatMessage(labels.cancel)}</Button>
|
||||
</FormButtons>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
11
src/app/(main)/invite/InvitePage.tsx
Normal file
11
src/app/(main)/invite/InvitePage.tsx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
'use client';
|
||||
|
||||
import { InviteForm } from './InviteForm';
|
||||
|
||||
export default function InvitePage() {
|
||||
return (
|
||||
<section style={{ marginBottom: 60 }}>
|
||||
<InviteForm />
|
||||
</section>
|
||||
);
|
||||
}
|
||||
10
src/app/(main)/invite/page.tsx
Normal file
10
src/app/(main)/invite/page.tsx
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import { Metadata } from 'next';
|
||||
import InvitePage from './InvitePage';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Join team',
|
||||
};
|
||||
|
||||
export default function () {
|
||||
return <InvitePage />;
|
||||
}
|
||||
|
|
@ -71,6 +71,15 @@ export function TeamEditForm({ teamId, allowEdit }: { teamId: string; allowEdit?
|
|||
</Flexbox>
|
||||
</FormRow>
|
||||
)}
|
||||
<FormRow label={formatMessage(labels.invitationLink)}>
|
||||
<Flexbox gap={10}>
|
||||
<TextField
|
||||
value={`${window.location.host}/invite?accessCode=${accessCode}`}
|
||||
readOnly
|
||||
allowCopy
|
||||
/>
|
||||
</Flexbox>
|
||||
</FormRow>
|
||||
{allowEdit && (
|
||||
<FormButtons>
|
||||
<SubmitButton variant="primary">{formatMessage(labels.save)}</SubmitButton>
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ export const labels = defineMessages({
|
|||
member: { id: 'label.member', defaultMessage: 'Member' },
|
||||
members: { id: 'label.members', defaultMessage: 'Members' },
|
||||
accessCode: { id: 'label.access-code', defaultMessage: 'Access code' },
|
||||
invitationLink: { id: 'label.invitation-link', defaultMessage: 'Invitation link' },
|
||||
teamId: { id: 'label.team-id', defaultMessage: 'Team ID' },
|
||||
team: { id: 'label.team', defaultMessage: 'Team' },
|
||||
teamName: { id: 'label.team-name', defaultMessage: 'Team name' },
|
||||
|
|
|
|||
|
|
@ -235,6 +235,7 @@
|
|||
"label.websites": "Websites",
|
||||
"label.window": "Window",
|
||||
"label.yesterday": "Yesterday",
|
||||
"label.invitation-link": "邀请链接",
|
||||
"message.action-confirmation": "Type {confirmation} in the box below to confirm.",
|
||||
"message.active-users": "{x} current {x, plural, one {visitor} other {visitors}}",
|
||||
"message.collected-data": "Collected data",
|
||||
|
|
|
|||
|
|
@ -236,6 +236,7 @@
|
|||
"label.websites": "网站",
|
||||
"label.window": "窗口",
|
||||
"label.yesterday": "昨天",
|
||||
"label.invitation-link": "邀请链接",
|
||||
"message.action-confirmation": "请在下方输入框中输入 {confirmation} 以确认操作。",
|
||||
"message.active-users": "当前在线 {x} 位访客",
|
||||
"message.collected-data": "已收集的数据",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue