Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { PlusOutlined, DeleteOutlined, EditOutlined } from '@ant-design/icons';
import { useAllowedUsersList, useAllowedUsersValidation } from '@app/hooks/useAllowedUsers';
import { AllowedUsersSettings, AllowedUsersMode, AllowedUser } from '@app/types/allowedUsers.types';
import * as S from './NPubManagement.styles';
import { TableContainer } from '../TiersConfig/TiersConfig.styles';

interface NPubManagementProps {
settings: AllowedUsersSettings;
Expand Down Expand Up @@ -158,19 +159,22 @@ export const NPubManagement: React.FC<NPubManagementProps> = ({
</Space>
</S.TabHeader>

<Table
columns={columns}
dataSource={users}
loading={loading}
pagination={{
current: pagination.page,
pageSize: pagination.page_size,
total: pagination.total_items,
showSizeChanger: false,
showTotal: (total) => `Total ${total} users`
}}
rowKey="npub"
/>
<TableContainer>
<Table
columns={columns}
dataSource={users}
loading={loading}

pagination={{
current: pagination.page,
pageSize: pagination.page_size,
total: pagination.total_items,
showSizeChanger: false,
showTotal: (total) => `Total ${total} users`
}}
rowKey="npub"
/>
</TableContainer>

{/* Add User Modal */}
<Modal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export const PermissionExplanations = styled.div`
ul {
margin: 0;
padding-left: 1.25rem;

li {
margin-bottom: 0.5rem;
font-size: 13px;
Expand All @@ -100,25 +100,27 @@ export const PermissionExplanations = styled.div`
export const ForcedSelectWrapper = styled.div<{ $isForced: boolean }>`
.ant-select {
width: 100%;

.ant-select-arrow{
color: ${(props) => (!props.$isForced ? `var(--text-main-color)` : `var(--text-light-color)`)};
}
.ant-select-selector {
background-color: ${props => props.$isForced ? '#1a1d35' : '#25284B'} !important;
border: ${props => props.$isForced ? '1px solid #434343' : '1px solid #d9d9d9'} !important;
color: ${props => props.$isForced ? '#8c8c8c' : '#d9d9d9'} !important;
background-color: ${(props) => (props.$isForced ? '#1a1d35' : '#25284B')} !important;
border: ${(props) => (props.$isForced ? '1px solid #434343' : '1px solid #d9d9d9')} !important;
color: ${(props) => (props.$isForced ? '#8c8c8c' : '#d9d9d9')} !important;
}

.ant-select-selection-item {
color: ${props => props.$isForced ? '#8c8c8c' : '#d9d9d9'} !important;
color: ${(props) => (props.$isForced ? '#8c8c8c' : '#d9d9d9')} !important;
}

&.ant-select-disabled {
.ant-select-selector {
background-color: ${props => props.$isForced ? '#1a1d35' : '#25284B'} !important;
border: ${props => props.$isForced ? '1px solid #434343' : '1px solid #d9d9d9'} !important;
background-color: ${(props) => (props.$isForced ? '#1a1d35' : '#25284B')} !important;
border: ${(props) => (props.$isForced ? '1px solid #434343' : '1px solid #d9d9d9')} !important;
}

.ant-select-selection-item {
color: ${props => props.$isForced ? '#8c8c8c' : '#d9d9d9'} !important;
color: ${(props) => (props.$isForced ? '#8c8c8c' : '#d9d9d9')} !important;
}
}
}
Expand Down
110 changes: 63 additions & 47 deletions src/components/allowed-users/components/TierEditor/TierEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import React, { useState, useEffect } from 'react';
import { Input, Select, Checkbox, Space, Typography, Alert } from 'antd';
import {
TierDisplayFormat,
DataUnit,
validateTierFormat,
import { Select, Checkbox, Space, Typography, Alert } from 'antd';
import {
TierDisplayFormat,
DataUnit,
validateTierFormat,
displayToFriendlyString,
bytesToDisplayFormat,
TIER_VALIDATION
TIER_VALIDATION,
} from '@app/utils/tierConversion.utils';
import { AllowedUsersTier } from '@app/types/allowedUsers.types';
import { StyledInput } from '@app/styles/themes/reusableComponentStyles';
import styled from 'styled-components';

const { Text } = Typography;
const { Option } = Select;
Expand All @@ -21,12 +23,25 @@ interface TierEditorProps {
showPrice?: boolean;
}

const PreviewTextWrapper = styled.div`
display: flex;
flex-direction: column;
gap: 1rem;
.ant-typography {
color: var(--text-main-color);
}
`;
const SelectWrapper = styled.div`
.ant-select-arrow {
color: var(--text-main-color);
}
`
export const TierEditor: React.FC<TierEditorProps> = ({
tier,
onTierChange,
disabled = false,
showName = true,
showPrice = true
showPrice = true,
}) => {
// Convert backend format to display format for editing
const [displayFormat, setDisplayFormat] = useState<TierDisplayFormat>(() => {
Expand All @@ -49,34 +64,39 @@ export const TierEditor: React.FC<TierEditorProps> = ({
const updatedTier: AllowedUsersTier = {
name,
price_sats: priceSats,
monthly_limit_bytes: displayFormat.unlimited ? 0 :
Math.round(displayFormat.value * getUnitMultiplier(displayFormat.unit)),
unlimited: displayFormat.unlimited
monthly_limit_bytes: displayFormat.unlimited
? 0
: Math.round(displayFormat.value * getUnitMultiplier(displayFormat.unit)),
unlimited: displayFormat.unlimited,
};
onTierChange(updatedTier);
}
}, [displayFormat, name, priceSats, isValid, onTierChange]);

const getUnitMultiplier = (unit: DataUnit): number => {
switch (unit) {
case 'MB': return 1048576; // 1024 * 1024
case 'GB': return 1073741824; // 1024 * 1024 * 1024
case 'TB': return 1099511627776; // 1024 * 1024 * 1024 * 1024
default: return 1048576;
case 'MB':
return 1048576; // 1024 * 1024
case 'GB':
return 1073741824; // 1024 * 1024 * 1024
case 'TB':
return 1099511627776; // 1024 * 1024 * 1024 * 1024
default:
return 1048576;
}
};

const handleValueChange = (value: string) => {
const numericValue = parseFloat(value) || 0;
setDisplayFormat(prev => ({ ...prev, value: numericValue }));
setDisplayFormat((prev) => ({ ...prev, value: numericValue }));
};

const handleUnitChange = (unit: DataUnit) => {
setDisplayFormat(prev => ({ ...prev, unit }));
setDisplayFormat((prev) => ({ ...prev, unit }));
};

const handleUnlimitedChange = (unlimited: boolean) => {
setDisplayFormat(prev => ({ ...prev, unlimited }));
setDisplayFormat((prev) => ({ ...prev, unlimited }));
};

const handleNameChange = (value: string) => {
Expand All @@ -94,7 +114,7 @@ export const TierEditor: React.FC<TierEditorProps> = ({
{showName && (
<div>
<Text strong>Tier Name</Text>
<Input
<StyledInput
value={name}
onChange={(e) => handleNameChange(e.target.value)}
placeholder="Enter tier name"
Expand All @@ -108,7 +128,7 @@ export const TierEditor: React.FC<TierEditorProps> = ({
{showPrice && (
<div>
<Text strong>Price (sats)</Text>
<Input
<StyledInput
type="number"
value={priceSats}
onChange={(e) => handlePriceChange(e.target.value)}
Expand All @@ -123,7 +143,7 @@ export const TierEditor: React.FC<TierEditorProps> = ({
{/* Data Limit */}
<div>
<Text strong>Monthly Data Limit</Text>

{/* Unlimited Checkbox */}
<div style={{ marginTop: 8, marginBottom: 8 }}>
<Checkbox
Expand All @@ -138,7 +158,7 @@ export const TierEditor: React.FC<TierEditorProps> = ({
{/* Value and Unit Inputs */}
{!displayFormat.unlimited && (
<Space.Compact style={{ width: '100%' }}>
<Input
<StyledInput
type="number"
value={displayFormat.value || ''}
onChange={(e) => handleValueChange(e.target.value)}
Expand All @@ -147,43 +167,39 @@ export const TierEditor: React.FC<TierEditorProps> = ({
min={TIER_VALIDATION.MIN_VALUE}
style={{ flex: 1 }}
/>
<Select
value={displayFormat.unit}
onChange={handleUnitChange}
disabled={disabled}
style={{ width: 80 }}
>
<Option value="MB">MB</Option>
<Option value="GB">GB</Option>
<Option value="TB">TB</Option>
</Select>
<SelectWrapper>
<Select value={displayFormat.unit} onChange={handleUnitChange} disabled={disabled} style={{ width: 80 }}>
<Option value="MB">MB</Option>
<Option value="GB">GB</Option>
<Option value="TB">TB</Option>
</Select>
</SelectWrapper>
</Space.Compact>
)}

{/* Preview */}
<div style={{ marginTop: 8 }}>
<Text type="secondary">
Preview: {displayToFriendlyString(displayFormat)}
</Text>
</div>
<PreviewTextWrapper>
<div style={{ marginTop: 8 }}>
<Text color="" type="secondary">
Preview: {displayToFriendlyString(displayFormat)}
</Text>
</div>
</PreviewTextWrapper>

{/* Validation Error */}
{!isValid && validation.error && (
<Alert
message={validation.error}
type="error"
style={{ marginTop: 8 }}
showIcon
/>
<Alert message={validation.error} type="error" style={{ marginTop: 8 }} showIcon />
)}
</div>

{/* Helpful Information */}
<div style={{ marginTop: 8 }}>
<Text type="secondary" style={{ fontSize: '12px' }}>
Valid range: 1 MB to 1 TB
</Text>
</div>
<PreviewTextWrapper>
<div style={{ marginTop: 8 }}>
<Text type="secondary" style={{ fontSize: '12px' }}>
Valid range: 1 MB to 1 TB
</Text>
</div>
</PreviewTextWrapper>
</Space>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,30 @@ export const TiersHeader = styled.div`
}
`;

export const TableContainer = styled.div`
border-radius: 12px;
margin: 0 2px;
padding-bottom: 1.5rem;
background-color: var(--background-color);
border: 1px solid var(--border-base-color);
.ant-table {
border-radius: 12px;
}
.ant-table-tbody {
background-color: var(--layout-sider-bg-color);
}
.ant-table-placeholder .ant-table-cell {
background-color: var(--layout-sider-bg-color);
transition: none;
}
.ant-table-placeholder .ant-table-cell:hover {
background-color: var(--layout-sider-bg-color);
}
.ant-empty-description {
color: var(--text-light-color);
}
`;

export const TiersTitle = styled.h3`
margin: 0;
color: var(--text-main-color);
Expand All @@ -36,5 +60,5 @@ interface PriceProps {

export const Price = styled.span<PriceProps>`
font-weight: 600;
color: ${({ $isFree }) => $isFree ? 'var(--success-color)' : 'var(--primary-color)'};
`;
color: ${({ $isFree }) => ($isFree ? 'var(--success-color)' : 'var(--primary-color)')};
`;
Original file line number Diff line number Diff line change
Expand Up @@ -345,13 +345,15 @@ export const TiersConfig: React.FC<TiersConfigProps> = ({
</Radio.Group>
</div>
) : (
<Table
columns={columns}
dataSource={settings.tiers.map((tier, index) => ({ ...tier, key: index }))}
pagination={false}
size="small"
locale={{ emptyText: 'No tiers configured' }}
/>
<S.TableContainer>
<Table
columns={columns}
dataSource={settings.tiers.map((tier, index) => ({ ...tier, key: index }))}
pagination={false}
size="small"
locale={{ emptyText: 'No tiers configured' }}
/>
</S.TableContainer>
)}

<Modal
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import styled from 'styled-components';
import { FONT_SIZE, FONT_WEIGHT, media } from '@app/styles/themes/constants';
import { Card } from 'antd';

export const Container = styled.div`
padding: 1.5rem;
Expand Down Expand Up @@ -64,4 +65,9 @@ export const ChangesIndicator = styled.span`
color: var(--warning-color);
font-size: 14px;
font-style: italic;
`;
export const ContentCard = styled(Card)`
background: var(--secondary-background-color);
border-color: var(--border-base-color);

`;
Loading
Loading