diff --git a/src/client/components/PageHeader.tsx b/src/client/components/PageHeader.tsx
new file mode 100644
index 0000000..df35ac0
--- /dev/null
+++ b/src/client/components/PageHeader.tsx
@@ -0,0 +1,14 @@
+import React from 'react';
+
+export const PageHeader: React.FC<{
+ title: string;
+ action?: React.ReactNode;
+}> = React.memo((props) => {
+ return (
+
+
{props.title}
+ {props.action}
+
+ );
+});
+PageHeader.displayName = 'PageHeader';
diff --git a/src/client/components/WebsiteList.tsx b/src/client/components/WebsiteList.tsx
index 7aed08f..8b7c88d 100644
--- a/src/client/components/WebsiteList.tsx
+++ b/src/client/components/WebsiteList.tsx
@@ -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 (
-
-
Websites
-
- }
- size="large"
- onClick={() => setIsModalOpen(true)}
- >
- Add Website
-
-
-
+
+ }
+ size="large"
+ onClick={() => setIsModalOpen(true)}
+ >
+ Add Website
+
+
+ }
+ />
diff --git a/src/client/components/modals/NotificationInfo/index.tsx b/src/client/components/modals/NotificationInfo/index.tsx
new file mode 100644
index 0000000..42d6ad5
--- /dev/null
+++ b/src/client/components/modals/NotificationInfo/index.tsx
@@ -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 {}
+export const NotificationInfoModal: React.FC =
+ 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 ;
+ }, [notificationType]);
+
+ return (
+
+
+
+
+
+
+
+
+
+ {form}
+
+
+ );
+ });
+NotificationInfoModal.displayName = 'NotificationInfoModal';
diff --git a/src/client/components/modals/NotificationInfo/strategies/index.ts b/src/client/components/modals/NotificationInfo/strategies/index.ts
new file mode 100644
index 0000000..9df1f8e
--- /dev/null
+++ b/src/client/components/modals/NotificationInfo/strategies/index.ts
@@ -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,
+ },
+];
diff --git a/src/client/components/modals/NotificationInfo/strategies/smtp.tsx b/src/client/components/modals/NotificationInfo/strategies/smtp.tsx
new file mode 100644
index 0000000..67fb8b8
--- /dev/null
+++ b/src/client/components/modals/NotificationInfo/strategies/smtp.tsx
@@ -0,0 +1,43 @@
+import { Checkbox, Form, Input, InputNumber, Select } from 'antd';
+import React from 'react';
+
+export const NotificationSMTP: React.FC = React.memo(() => {
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+});
+NotificationSMTP.displayName = 'NotificationSMTP';
diff --git a/src/client/pages/Settings/NotificationList.tsx b/src/client/pages/Settings/NotificationList.tsx
new file mode 100644
index 0000000..0b6481c
--- /dev/null
+++ b/src/client/pages/Settings/NotificationList.tsx
@@ -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 (
+
+
+ }
+ size="large"
+ onClick={() => setOpen(true)}
+ >
+ New
+
+
+ }
+ />
+
+ (
+ edit]}>
+
+
+ )}
+ />
+
+ setOpen(false)}
+ />
+
+ );
+});
+NotificationList.displayName = 'NotificationList';
diff --git a/src/client/pages/Settings/index.tsx b/src/client/pages/Settings/index.tsx
index ee2f488..81d235f 100644
--- a/src/client/pages/Settings/index.tsx
+++ b/src/client/pages/Settings/index.tsx
@@ -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(() => {
} />
} />
} />
+ } />