feat: add basic notification settings ui
This commit is contained in:
parent
254c5079c4
commit
c180d1d5f1
14
src/client/components/PageHeader.tsx
Normal file
14
src/client/components/PageHeader.tsx
Normal file
@ -0,0 +1,14 @@
|
||||
import React from 'react';
|
||||
|
||||
export const PageHeader: React.FC<{
|
||||
title: string;
|
||||
action?: React.ReactNode;
|
||||
}> = React.memo((props) => {
|
||||
return (
|
||||
<div className="h-24 flex items-center">
|
||||
<div className="text-2xl flex-1">{props.title}</div>
|
||||
{props.action}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
PageHeader.displayName = 'PageHeader';
|
@ -18,6 +18,7 @@ import { useRequest } from '../hooks/useRequest';
|
||||
import { useUserStore } from '../store/user';
|
||||
import { useEvent } from '../hooks/useEvent';
|
||||
import { useNavigate } from 'react-router';
|
||||
import { PageHeader } from './PageHeader';
|
||||
|
||||
export const WebsiteList: React.FC = React.memo(() => {
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
@ -43,19 +44,21 @@ export const WebsiteList: React.FC = React.memo(() => {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="h-24 flex items-center">
|
||||
<div className="text-2xl flex-1">Websites</div>
|
||||
<div>
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<PlusOutlined />}
|
||||
size="large"
|
||||
onClick={() => setIsModalOpen(true)}
|
||||
>
|
||||
Add Website
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<PageHeader
|
||||
title="Websites"
|
||||
action={
|
||||
<div>
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<PlusOutlined />}
|
||||
size="large"
|
||||
onClick={() => setIsModalOpen(true)}
|
||||
>
|
||||
Add Website
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
||||
<WebsiteListTable workspaceId={currentWorkspace.id} />
|
||||
|
||||
|
55
src/client/components/modals/NotificationInfo/index.tsx
Normal file
55
src/client/components/modals/NotificationInfo/index.tsx
Normal file
@ -0,0 +1,55 @@
|
||||
import { Form, Input, Modal, ModalProps, Select } from 'antd';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { notificationStrategies } from './strategies';
|
||||
|
||||
interface NotificationInfoModalProps
|
||||
extends Pick<ModalProps, 'open' | 'onOk' | 'onCancel'> {}
|
||||
export const NotificationInfoModal: React.FC<NotificationInfoModalProps> =
|
||||
React.memo((props) => {
|
||||
const [notificationType, setNotificationType] = useState(
|
||||
notificationStrategies[0].name
|
||||
);
|
||||
|
||||
const form = useMemo(() => {
|
||||
const strategy = notificationStrategies.find(
|
||||
(s) => s.name === notificationType
|
||||
);
|
||||
|
||||
if (!strategy) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const Component = strategy.form;
|
||||
|
||||
return <Component />;
|
||||
}, [notificationType]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title="Notification"
|
||||
open={props.open}
|
||||
onOk={props.onOk}
|
||||
onCancel={props.onCancel}
|
||||
>
|
||||
<Form layout="vertical">
|
||||
<Form.Item label="Notification Type">
|
||||
<Select
|
||||
value={notificationType}
|
||||
onChange={(val) => setNotificationType(val)}
|
||||
>
|
||||
{notificationStrategies.map((s) => (
|
||||
<Select.Option value={s.name}>{s.label}</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="Display Name" name="name">
|
||||
<Input />
|
||||
</Form.Item>
|
||||
|
||||
{form}
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
});
|
||||
NotificationInfoModal.displayName = 'NotificationInfoModal';
|
@ -0,0 +1,16 @@
|
||||
import React from 'react';
|
||||
import { NotificationSMTP } from './smtp';
|
||||
|
||||
interface NotificationStrategy {
|
||||
label: string;
|
||||
name: string;
|
||||
form: React.ComponentType;
|
||||
}
|
||||
|
||||
export const notificationStrategies: NotificationStrategy[] = [
|
||||
{
|
||||
label: 'Email(SMTP)',
|
||||
name: 'smtp',
|
||||
form: NotificationSMTP,
|
||||
},
|
||||
];
|
@ -0,0 +1,43 @@
|
||||
import { Checkbox, Form, Input, InputNumber, Select } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
export const NotificationSMTP: React.FC = React.memo(() => {
|
||||
return (
|
||||
<>
|
||||
<Form.Item label="Host" name="hostname">
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item label="Port" name="port">
|
||||
<InputNumber max={65535} min={1} />
|
||||
</Form.Item>
|
||||
<Form.Item label="Security" name="security">
|
||||
<Select>
|
||||
<Select.Option value={false}>None / STARTTLS (25, 587)</Select.Option>
|
||||
<Select.Option value={true}>TLS (465)</Select.Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form name="ignoreTLS">
|
||||
<Checkbox>Ignore TLS Error</Checkbox>
|
||||
</Form>
|
||||
<Form.Item label="Username" name="username">
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item label="Password" name="password">
|
||||
<Input.Password />
|
||||
</Form.Item>
|
||||
<Form.Item label="From Email" name="from">
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item label="To Email" name="to">
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item label="CC" name="cc">
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item label="BCC" name="bcc">
|
||||
<Input />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
});
|
||||
NotificationSMTP.displayName = 'NotificationSMTP';
|
56
src/client/pages/Settings/NotificationList.tsx
Normal file
56
src/client/pages/Settings/NotificationList.tsx
Normal file
@ -0,0 +1,56 @@
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import { Button, List } from 'antd';
|
||||
import React, { useState } from 'react';
|
||||
import { NotificationInfoModal } from '../../components/modals/NotificationInfo';
|
||||
import { PageHeader } from '../../components/PageHeader';
|
||||
import { useEvent } from '../../hooks/useEvent';
|
||||
|
||||
export const NotificationList: React.FC = React.memo(() => {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const handleOk = useEvent(() => {
|
||||
console.log('ok');
|
||||
setOpen(false);
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<PageHeader
|
||||
title="Notification List"
|
||||
action={
|
||||
<div>
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<PlusOutlined />}
|
||||
size="large"
|
||||
onClick={() => setOpen(true)}
|
||||
>
|
||||
New
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
||||
<List
|
||||
bordered={true}
|
||||
dataSource={[
|
||||
{ id: '1', name: 'Email Notify' },
|
||||
{ id: '1', name: 'Email Notify' },
|
||||
{ id: '1', name: 'Email Notify' },
|
||||
]}
|
||||
renderItem={(item) => (
|
||||
<List.Item actions={[<Button>edit</Button>]}>
|
||||
<List.Item.Meta title={item.name} />
|
||||
</List.Item>
|
||||
)}
|
||||
/>
|
||||
|
||||
<NotificationInfoModal
|
||||
open={open}
|
||||
onOk={handleOk}
|
||||
onCancel={() => setOpen(false)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
NotificationList.displayName = 'NotificationList';
|
@ -4,6 +4,7 @@ import { Routes, Route, useLocation, useNavigate } from 'react-router-dom';
|
||||
import { WebsiteInfo } from '../../components/WebsiteInfo';
|
||||
import { WebsiteList } from '../../components/WebsiteList';
|
||||
import { useEvent } from '../../hooks/useEvent';
|
||||
import { NotificationList } from './NotificationList';
|
||||
|
||||
export const SettingsPage: React.FC = React.memo(() => {
|
||||
const navigate = useNavigate();
|
||||
@ -14,6 +15,10 @@ export const SettingsPage: React.FC = React.memo(() => {
|
||||
key: 'websites',
|
||||
label: 'Websites',
|
||||
},
|
||||
{
|
||||
key: 'notifications',
|
||||
label: 'Notifications',
|
||||
},
|
||||
];
|
||||
|
||||
const onClick: MenuProps['onClick'] = useEvent((e) => {
|
||||
@ -40,6 +45,7 @@ export const SettingsPage: React.FC = React.memo(() => {
|
||||
<Route path="/" element={<WebsiteList />} />
|
||||
<Route path="/websites" element={<WebsiteList />} />
|
||||
<Route path="/website/:websiteId" element={<WebsiteInfo />} />
|
||||
<Route path="/notifications" element={<NotificationList />} />
|
||||
</Routes>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user