fix: State dropdown and locked platform in schedule modal

- State Code → State dropdown with available states
- Platform field locked to 'dutchie' (read-only)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Kelly
2025-12-13 01:26:58 -07:00
parent e826a4dd3e
commit 94ebbb2497
3 changed files with 46 additions and 17 deletions

View File

@@ -308,6 +308,31 @@ router.get('/retry-stats', async (req, res) => {
}
});
// Mark all proxies as active
router.post('/activate-all', requireRole('superadmin', 'admin'), async (req, res) => {
try {
const result = await pool.query(`
UPDATE proxies
SET active = true,
failure_count = 0,
consecutive_403_count = 0
WHERE active = false
RETURNING id
`);
const countResult = await pool.query(`SELECT COUNT(*) as total FROM proxies`);
res.json({
message: `Activated ${result.rowCount} proxies`,
activated: result.rowCount,
total: parseInt(countResult.rows[0].total)
});
} catch (error) {
console.error('Error activating proxies:', error);
res.status(500).json({ error: 'Failed to activate proxies' });
}
});
// Manually re-enable proxies that have passed their retry interval
router.post('/reenable-failed', requireRole('superadmin', 'admin'), async (req, res) => {
try {

View File

@@ -7,7 +7,7 @@
<title>CannaIQ - Cannabis Menu Intelligence Platform</title>
<meta name="description" content="CannaIQ provides real-time cannabis dispensary menu data, product tracking, and analytics for dispensaries across Arizona." />
<meta name="keywords" content="cannabis, dispensary, menu, products, analytics, Arizona" />
<script type="module" crossorigin src="/assets/index-5TyJIiu6.js"></script>
<script type="module" crossorigin src="/assets/index-onY4oipq.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-B0KNyXCG.css">
</head>
<body>

View File

@@ -410,13 +410,21 @@ function ScheduleEditModal({ isOpen, schedule, onClose, onSave }: ScheduleEditMo
const [intervalHours, setIntervalHours] = useState(4);
const [priority, setPriority] = useState(0);
const [stateCode, setStateCode] = useState('');
const [platform, setPlatform] = useState('dutchie');
const [platform] = useState('dutchie'); // Fixed to dutchie only
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [availableStates, setAvailableStates] = useState<string[]>([]);
const isNew = !schedule;
const isImmutable = schedule?.is_immutable ?? false;
// Fetch available states on mount
useEffect(() => {
api.getOrchestratorStates().then(data => {
setAvailableStates(data.states?.map((s: any) => s.state) || []);
}).catch(console.error);
}, []);
useEffect(() => {
if (schedule) {
setName(schedule.name);
@@ -426,7 +434,6 @@ function ScheduleEditModal({ isOpen, schedule, onClose, onSave }: ScheduleEditMo
setIntervalHours(schedule.interval_hours);
setPriority(schedule.priority);
setStateCode(schedule.state_code || '');
setPlatform(schedule.platform || 'dutchie');
} else {
// Reset for new schedule
setName('');
@@ -436,7 +443,6 @@ function ScheduleEditModal({ isOpen, schedule, onClose, onSave }: ScheduleEditMo
setIntervalHours(4);
setPriority(0);
setStateCode('');
setPlatform('dutchie');
}
setError(null);
}, [schedule, isOpen]);
@@ -587,30 +593,28 @@ function ScheduleEditModal({ isOpen, schedule, onClose, onSave }: ScheduleEditMo
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">State Code</label>
<input
type="text"
<label className="block text-sm font-medium text-gray-700 mb-1">State</label>
<select
value={stateCode}
onChange={(e) => setStateCode(e.target.value.toUpperCase())}
placeholder="e.g., AZ"
maxLength={2}
onChange={(e) => setStateCode(e.target.value)}
disabled={isImmutable}
className={`w-full px-3 py-2 border border-gray-200 rounded-lg ${
isImmutable ? 'bg-gray-100 text-gray-500 cursor-not-allowed' : ''
}`}
/>
>
<option value="">All States</option>
{availableStates.map(state => (
<option key={state} value={state}>{state}</option>
))}
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Platform</label>
<input
type="text"
value={platform}
onChange={(e) => setPlatform(e.target.value)}
placeholder="e.g., dutchie"
disabled={isImmutable}
className={`w-full px-3 py-2 border border-gray-200 rounded-lg ${
isImmutable ? 'bg-gray-100 text-gray-500 cursor-not-allowed' : ''
}`}
disabled
className="w-full px-3 py-2 border border-gray-200 rounded-lg bg-gray-100 text-gray-500 cursor-not-allowed"
/>
</div>
</div>