Skip to content

Commit ca1e0c4

Browse files
Merge pull request #42 from HORNET-Storage/feature/generic-settings
Feature/generic settings
2 parents fdca8a6 + 74d53bc commit ca1e0c4

32 files changed

+5364
-16
lines changed

.env.example

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1 @@
1-
REACT_APP_BASE_URL=http://localhost:9002
2-
REACT_APP_ASSETS_BUCKET=https://lightence-assets.s3.amazonaws.com
3-
4-
# more info https://create-react-app.dev/docs/advanced-configuration
5-
ESLINT_NO_DEV_ERRORS=
6-
TSC_COMPILE_ON_ERROR=
1+
NODE_OPTIONS=--openssl-legacy-provider

package.json

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,15 @@
8383
"workbox-streams": "^5.1.3"
8484
},
8585
"scripts": {
86-
"start": "yarn buildThemes && craco start",
87-
"build": "yarn buildThemes && craco build",
88-
"test": "craco test",
89-
"eject": "craco eject",
86+
"start": "NODE_OPTIONS=--openssl-legacy-provider yarn buildThemes && NODE_OPTIONS=--openssl-legacy-provider craco start",
87+
"build": "NODE_OPTIONS=--openssl-legacy-provider yarn buildThemes && NODE_OPTIONS=--openssl-legacy-provider craco build",
88+
"test": "NODE_OPTIONS=--openssl-legacy-provider craco test",
89+
"eject": "NODE_OPTIONS=--openssl-legacy-provider craco eject",
9090
"lint": "eslint \"*/**/*.{js,ts,tsx}\" --fix",
9191
"lint:styles": "stylelint '*/**/*.{js,ts,tsx}'",
9292
"prepare": "husky install",
93-
"buildThemes": "lessc --js --clean-css=\"--s1 --advanced\" src/styles/themes/main.less public/themes/main.css"
93+
"update-browserslist": "npx update-browserslist-db@latest",
94+
"buildThemes": "NODE_OPTIONS=--openssl-legacy-provider lessc --js --clean-css=\"--s1 --advanced\" src/styles/themes/main.less public/themes/main.css"
9495
},
9596
"browserslist": [
9697
">0.2%",

src/@types/event-target.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
interface EventTarget {
2+
state?: 'activated';
3+
}

src/components/common/BaseNotification/BaseNotification.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ interface Icons {
99
warning: React.ReactNode;
1010
error: React.ReactNode;
1111
mention: React.ReactNode;
12+
moderation: React.ReactNode;
1213
}
1314

14-
export type NotificationType = 'info' | 'mention' | 'success' | 'warning' | 'error';
15+
export type NotificationType = 'info' | 'mention' | 'success' | 'warning' | 'error' | 'moderation';
1516

1617
interface BaseNotificationProps {
1718
type: NotificationType;
@@ -27,6 +28,7 @@ export const BaseNotification: React.FC<BaseNotificationProps> = ({ type, mentio
2728
warning: <ExclamationCircleFilled />,
2829
error: <WarningFilled />,
2930
mention: mentionIconSrc,
31+
moderation: <WarningFilled />, // Using the same icon as error for moderation
3032
};
3133

3234
const icon = icons[type] || icons.warning;

src/components/layouts/main/sider/sidebarNavigation.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { useMemo } from 'react';
2-
import { DashboardOutlined, TableOutlined, StopOutlined, FlagOutlined } from '@ant-design/icons';
2+
import { DashboardOutlined, TableOutlined, StopOutlined, FlagOutlined, SettingOutlined } from '@ant-design/icons';
33
import { ReactComponent as NestIcon } from '@app/assets/icons/hive.svg';
44
import { ReactComponent as BtcIcon } from '@app/assets/icons/btc.svg';
55
import { ReactComponent as StatsIcon } from '@app/assets/icons/stats.svg';
@@ -31,6 +31,12 @@ export const useSidebarNavigation = (): SidebarNavigationItem[] => {
3131
url: '/relay-settings',
3232
icon: <StorageSettingsIcon />,
3333
},
34+
{
35+
title: 'Advanced Settings',
36+
key: 'advanced-settings',
37+
url: '/settings',
38+
icon: <SettingOutlined />,
39+
},
3440
{
3541
title: 'common.access-control',
3642
key: 'blocked-pubkeys',

src/components/router/AppRouter.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import React from 'react';
33
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
44
import { AuthGuard } from '@app/components/AuthGuard';
55
import AuthLayout from '@app/components/layouts/AuthLayout/AuthLayout';
6+
import SettingsPage from '@app/components/settings/SettingsPage';
67

78
AuthLayout.displayName = 'AuthLayout';
89
import LoginPage from '@app/pages/LoginPage';
@@ -74,6 +75,7 @@ const Logout = React.lazy(() => import('./Logout'));
7475
export const NFT_DASHBOARD_PATH = '/';
7576
export const MEDICAL_DASHBOARD_PATH = '/medical-dashboard';
7677
export const RELAY_SETTINGS_PATH = '/relay-settings';
78+
export const SETTINGS_PATH = '/settings';
7779
export const TABLES_PAGE_PATH = '/nostr-stats';
7880

7981
const MedicalDashboard = withLoading(MedicalDashboardPage);
@@ -114,6 +116,7 @@ const DataTables = withLoading(DataTablesPage);
114116
const Charts = withLoading(ChartsPage);
115117
const RelayStats = withLoading(RelayStatsPage);
116118
const RelaySettings = withLoading(RelaySettingsPage);
119+
const Settings = withLoading(SettingsPage);
117120
const BlockedPubkeys = withLoading(BlockedPubkeysPage);
118121

119122
// Maps
@@ -155,6 +158,7 @@ export const AppRouter: React.FC = () => {
155158
<Route path="media-manager" element={<MediaPage />} />
156159
<Route path="relay-stats" element={<RelayStats />} />
157160
<Route path={RELAY_SETTINGS_PATH} element={<RelaySettings />} />
161+
<Route path={`${SETTINGS_PATH}/*`} element={<Settings />} />
158162
<Route path="blocked-pubkeys" element={<BlockedPubkeys />} />
159163
<Route path="apps">
160164
<Route path="feed" element={<NewsFeed />} />
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import React from 'react';
2+
import { Form, Button, Card, Space, Alert, Spin } from 'antd';
3+
import { SaveOutlined, ReloadOutlined } from '@ant-design/icons';
4+
import styled from 'styled-components';
5+
6+
const StyledCard = styled(Card)`
7+
margin-bottom: 1.5rem;
8+
`;
9+
10+
const ButtonsContainer = styled.div`
11+
display: flex;
12+
justify-content: flex-end;
13+
margin-top: 1rem;
14+
`;
15+
16+
interface BaseSettingsFormProps {
17+
title: string;
18+
loading: boolean;
19+
error: Error | null;
20+
onSave: () => Promise<void>;
21+
onReset: () => void;
22+
children: React.ReactNode;
23+
}
24+
25+
const BaseSettingsForm: React.FC<BaseSettingsFormProps> = ({
26+
title,
27+
loading,
28+
error,
29+
onSave,
30+
onReset,
31+
children,
32+
}) => {
33+
const [form] = Form.useForm();
34+
const [saving, setSaving] = React.useState(false);
35+
36+
const handleSave = async () => {
37+
try {
38+
await form.validateFields();
39+
setSaving(true);
40+
await onSave();
41+
} catch (error) {
42+
console.error('Validation failed:', error);
43+
} finally {
44+
setSaving(false);
45+
}
46+
};
47+
48+
return (
49+
<StyledCard title={title}>
50+
{error && (
51+
<Alert
52+
message="Error"
53+
description={error.message}
54+
type="error"
55+
showIcon
56+
style={{ marginBottom: '1rem' }}
57+
/>
58+
)}
59+
60+
<Spin spinning={loading}>
61+
<Form
62+
form={form}
63+
layout="vertical"
64+
initialValues={{}}
65+
>
66+
{children}
67+
68+
<ButtonsContainer>
69+
<Space>
70+
<Button
71+
icon={<ReloadOutlined />}
72+
onClick={onReset}
73+
disabled={loading || saving}
74+
>
75+
Reset
76+
</Button>
77+
<Button
78+
type="primary"
79+
icon={<SaveOutlined />}
80+
onClick={handleSave}
81+
loading={saving}
82+
disabled={loading}
83+
>
84+
Save
85+
</Button>
86+
</Space>
87+
</ButtonsContainer>
88+
</Form>
89+
</Spin>
90+
</StyledCard>
91+
);
92+
};
93+
94+
export default BaseSettingsForm;
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import React from 'react';
2+
import { Form, Card, Alert, Spin } from 'antd';
3+
import styled from 'styled-components';
4+
5+
const StyledCard = styled(Card)`
6+
margin-bottom: 1rem;
7+
border: none;
8+
box-shadow: none;
9+
`;
10+
11+
interface BaseSettingsPanelProps {
12+
title?: string;
13+
loading: boolean;
14+
error: Error | null;
15+
children: React.ReactNode;
16+
extra?: React.ReactNode;
17+
}
18+
19+
const BaseSettingsPanel: React.FC<BaseSettingsPanelProps> = ({
20+
title,
21+
loading,
22+
error,
23+
children,
24+
extra,
25+
}) => {
26+
return (
27+
<StyledCard
28+
title={title}
29+
extra={extra}
30+
>
31+
{error && (
32+
<Alert
33+
message="Error"
34+
description={error.message}
35+
type="error"
36+
showIcon
37+
style={{ marginBottom: '1rem' }}
38+
/>
39+
)}
40+
41+
<Spin spinning={loading}>
42+
{children}
43+
</Spin>
44+
</StyledCard>
45+
);
46+
};
47+
48+
export default BaseSettingsPanel;

0 commit comments

Comments
 (0)