Initial commit

This commit is contained in:
Grae Jones
2026-02-03 15:45:39 -08:00
commit 3647b304a3
74 changed files with 27121 additions and 0 deletions

View File

@@ -0,0 +1,199 @@
import React, { useState } from 'react';
import { gatewayHealth } from '../../services/apiClient';
import { GATEWAY_URL } from '../../auth/authConfig';
const tabs = [
{ id: 'general', label: 'General' },
{ id: 'connection', label: 'Connection' },
{ id: 'notifications', label: 'Notifications' },
{ id: 'security', label: 'Security' },
];
export default function Settings({ sessionUser, sessionToken, onSignOut }) {
const [activeTab, setActiveTab] = useState('general');
const [tenantId, setTenantId] = useState(localStorage.getItem('adplatform_tenantId') || '');
const [healthResult, setHealthResult] = useState(null);
const [testing, setTesting] = useState(false);
const saveTenantId = () => {
if (tenantId.trim()) {
localStorage.setItem('adplatform_tenantId', tenantId.trim());
} else {
localStorage.removeItem('adplatform_tenantId');
}
};
const testConnection = async () => {
setTesting(true);
setHealthResult(null);
const result = await gatewayHealth();
setHealthResult(result);
setTesting(false);
};
return (
<div>
<div className="view-header">
<h1>Settings</h1>
</div>
<div className="settings-layout">
<nav className="settings-nav">
{tabs.map(tab => (
<button
key={tab.id}
className={`settings-nav-item ${activeTab === tab.id ? 'active' : ''}`}
onClick={() => setActiveTab(tab.id)}
>
{tab.label}
</button>
))}
</nav>
<div className="settings-content">
{activeTab === 'general' && (
<>
<div className="settings-section">
<h3>Profile</h3>
<div className="setting-row">
<div className="setting-info">
<div className="setting-label">Display Name</div>
<div className="setting-desc">{sessionUser?.name || 'Not set'}</div>
</div>
</div>
<div className="setting-row">
<div className="setting-info">
<div className="setting-label">Email</div>
<div className="setting-desc">{sessionUser?.email || 'Not set'}</div>
</div>
</div>
<div className="setting-row">
<div className="setting-info">
<div className="setting-label">Role</div>
<div className="setting-desc">{sessionUser?.role || 'User'}</div>
</div>
</div>
</div>
<div className="settings-section">
<h3>Tenant Configuration</h3>
<div className="form-group">
<label>Tenant ID (Google Ads Customer ID)</label>
<div className="input-row">
<input
className="form-input"
type="text"
value={tenantId}
onChange={e => setTenantId(e.target.value)}
placeholder="e.g. 123-456-7890"
/>
<button className="btn btn-primary btn-sm" onClick={saveTenantId}>Save</button>
</div>
<div style={{ fontSize: '13px', color: 'var(--color-text-muted)', marginTop: '-12px' }}>
This ID is sent as X-Tenant-Id header with API requests.
</div>
</div>
</div>
</>
)}
{activeTab === 'connection' && (
<>
<div className="settings-section">
<h3>Gateway Connection</h3>
<div className="setting-row">
<div className="setting-info">
<div className="setting-label">Gateway URL</div>
<div className="setting-value">{GATEWAY_URL}</div>
</div>
</div>
<div className="setting-row">
<div className="setting-info">
<div className="setting-label">Connection Test</div>
<div className="setting-desc">Verify the gateway is reachable and responding.</div>
</div>
<button className="btn btn-sm btn-outline" onClick={testConnection} disabled={testing}>
{testing ? 'Testing…' : 'Test Connection'}
</button>
</div>
{healthResult && (
<div className={healthResult.ok ? 'info-box' : 'error-box'} style={{ marginTop: '12px' }}>
{healthResult.ok
? '✓ Gateway is healthy and responding.'
: `✗ Connection failed: ${healthResult.error}`}
</div>
)}
</div>
<div className="settings-section">
<h3>Session Information</h3>
<div className="session-info-detailed">
<div className="detail-item">
<span className="detail-label">Session Token</span>
<span className="detail-value mono" style={{ wordBreak: 'break-all', fontSize: '12px' }}>
{sessionToken ? sessionToken.substring(0, 32) + '…' : 'None'}
</span>
</div>
<div className="detail-item">
<span className="detail-label">User ID</span>
<span className="detail-value mono">{sessionUser?.userId || '—'}</span>
</div>
<div className="detail-item">
<span className="detail-label">Client ID</span>
<span className="detail-value mono">{sessionUser?.clientId || '—'}</span>
</div>
<div className="detail-item">
<span className="detail-label">Session ID</span>
<span className="detail-value mono">{sessionUser?.sessionId || '—'}</span>
</div>
</div>
</div>
</>
)}
{activeTab === 'notifications' && (
<div className="settings-section">
<h3>Notification Preferences</h3>
<div className="setting-row">
<div className="setting-info">
<div className="setting-label">Campaign Alerts</div>
<div className="setting-desc">Receive alerts when campaigns need attention.</div>
</div>
<span style={{ fontSize: '13px', color: 'var(--color-text-muted)' }}>Coming soon</span>
</div>
<div className="setting-row">
<div className="setting-info">
<div className="setting-label">Budget Warnings</div>
<div className="setting-desc">Get notified when budgets are nearly exhausted.</div>
</div>
<span style={{ fontSize: '13px', color: 'var(--color-text-muted)' }}>Coming soon</span>
</div>
<div className="setting-row">
<div className="setting-info">
<div className="setting-label">Weekly Summary</div>
<div className="setting-desc">Receive a weekly performance summary email.</div>
</div>
<span style={{ fontSize: '13px', color: 'var(--color-text-muted)' }}>Coming soon</span>
</div>
</div>
)}
{activeTab === 'security' && (
<>
<div className="settings-section">
<h3>Authentication</h3>
<div className="setting-row">
<div className="setting-info">
<div className="setting-label">Sign Out</div>
<div className="setting-desc">End your current session and return to the login page.</div>
</div>
<button className="btn btn-sm btn-danger" onClick={onSignOut}>Sign Out</button>
</div>
</div>
</>
)}
</div>
</div>
</div>
);
}