feat: add SMS diagnostics admin check

This commit is contained in:
unknown
2026-07-16 16:23:12 +09:00
parent ae1f30592d
commit 9c4dac9a70
7 changed files with 146 additions and 2 deletions

View File

@@ -12,14 +12,15 @@ import {
updateAdminPurposeCode,
updateAdminUserTeam,
updateAdminUserRoles,
runSmsDiagnostics,
uploadAdminTeams,
uploadAdminUserRoles,
updateWatcher1Settings,
getWatcher1Settings,
} from '../api';
import { AdminExcelImportResult, AdminUser, PurposeCode, Role, Team, Watcher1Settings } from '../types';
import { AdminExcelImportResult, AdminUser, PurposeCode, Role, SmsDiagnosticsResult, Team, Watcher1Settings } from '../types';
type Tab = 'watcher' | 'purpose' | 'teams' | 'roles';
type Tab = 'watcher' | 'purpose' | 'teams' | 'roles' | 'sms';
const EMPTY_PURPOSE = {
code: '',
@@ -137,6 +138,7 @@ export const AdminManagementPage: React.FC = () => {
const [teamUploadResult, setTeamUploadResult] = useState<AdminExcelImportResult | null>(null);
const [userRoleUploadFile, setUserRoleUploadFile] = useState<File | null>(null);
const [userRoleUploadResult, setUserRoleUploadResult] = useState<AdminExcelImportResult | null>(null);
const [smsDiagnostics, setSmsDiagnostics] = useState<SmsDiagnosticsResult | null>(null);
const [notice, setNotice] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);
const [busy, setBusy] = useState(false);
@@ -169,6 +171,21 @@ export const AdminManagementPage: React.FC = () => {
}
};
const checkSms = async () => {
setBusy(true);
setError(null);
setNotice(null);
try {
const result = await runSmsDiagnostics();
setSmsDiagnostics(result);
setNotice(result.reachable ? 'SMS API 연결 점검이 완료되었습니다.' : 'SMS API 연결 점검에 실패했습니다.');
} catch (err) {
setError(err instanceof Error ? err.message : 'SMS API 연결 점검 실패');
} finally {
setBusy(false);
}
};
const editPurpose = (p: PurposeCode) => {
setEditingPurposeId(p.id);
setPurposeForm({
@@ -404,6 +421,7 @@ export const AdminManagementPage: React.FC = () => {
<button className={tab === 'purpose' ? 'tab-active' : ''} onClick={() => setTab('purpose')}> </button>
<button className={tab === 'teams' ? 'tab-active' : ''} onClick={() => setTab('teams')}> </button>
<button className={tab === 'roles' ? 'tab-active' : ''} onClick={() => setTab('roles')}></button>
<button className={tab === 'sms' ? 'tab-active' : ''} onClick={() => setTab('sms')}>SMS </button>
</div>
{tab === 'watcher' && (
@@ -579,6 +597,32 @@ export const AdminManagementPage: React.FC = () => {
</div>
</>
)}
{tab === 'sms' && (
<div className="card">
<div className="admin-upload-head">
<h3>SMS API </h3>
<button className="btn-primary" type="button" disabled={busy} onClick={() => void checkSms()}>
</button>
</div>
{smsDiagnostics ? (
<table className="table diagnostic-table">
<tbody>
<tr><th>Provider</th><td>{smsDiagnostics.provider}</td></tr>
<tr><th>URL</th><td>{smsDiagnostics.url || '-'}</td></tr>
<tr><th></th><td className={smsDiagnostics.reachable ? '' : 'text-danger'}>{smsDiagnostics.reachable ? '성공' : '실패'}</td></tr>
<tr><th>HTTP </th><td>{smsDiagnostics.httpStatus ?? '-'}</td></tr>
<tr><th></th><td>{smsDiagnostics.elapsedMs} ms</td></tr>
<tr><th></th><td>{new Date(smsDiagnostics.checkedAt).toLocaleString()}</td></tr>
<tr><th></th><td className={smsDiagnostics.error ? 'text-danger' : ''}>{smsDiagnostics.error ?? '-'}</td></tr>
</tbody>
</table>
) : (
<p className="muted"> SMS API URL로 .</p>
)}
</div>
)}
</div>
);
};