|
|
@ -15,6 +15,9 @@ import { |
|
|
ExternalLink |
|
|
ExternalLink |
|
|
} from 'lucide-react'; |
|
|
} from 'lucide-react'; |
|
|
|
|
|
|
|
|
|
|
|
const HOURS_LIST = Array.from({ length: 24 }, (_, i) => i.toString().padStart(2, '0')); |
|
|
|
|
|
const MINUTES_LIST = Array.from({ length: 60 }, (_, i) => i.toString().padStart(2, '0')); |
|
|
|
|
|
|
|
|
function App() { |
|
|
function App() { |
|
|
const [activeTab, setActiveTab] = useState('crawlers'); |
|
|
const [activeTab, setActiveTab] = useState('crawlers'); |
|
|
const [crawlers, setCrawlers] = useState([]); |
|
|
const [crawlers, setCrawlers] = useState([]); |
|
|
@ -47,6 +50,34 @@ function App() { |
|
|
const [formIsActive, setFormIsActive] = useState(true); |
|
|
const [formIsActive, setFormIsActive] = useState(true); |
|
|
const [formError, setFormError] = useState(''); |
|
|
const [formError, setFormError] = useState(''); |
|
|
|
|
|
|
|
|
|
|
|
// Parse hour and minute from form time states |
|
|
|
|
|
const [startH, startM] = (formStartHour || '08:00').split(':'); |
|
|
|
|
|
const [endH, endM] = (formEndHour || '23:00').split(':'); |
|
|
|
|
|
|
|
|
|
|
|
const updateStartHour = (h) => { |
|
|
|
|
|
const parts = (formStartHour || '08:00').split(':'); |
|
|
|
|
|
const m = parts.length > 1 ? parts[1] : '00'; |
|
|
|
|
|
setFormStartHour(`${h}:${m}`); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const updateStartMinute = (m) => { |
|
|
|
|
|
const parts = (formStartHour || '08:00').split(':'); |
|
|
|
|
|
const h = parts.length > 0 ? parts[0] : '08'; |
|
|
|
|
|
setFormStartHour(`${h}:${m}`); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const updateEndHour = (h) => { |
|
|
|
|
|
const parts = (formEndHour || '23:00').split(':'); |
|
|
|
|
|
const m = parts.length > 1 ? parts[1] : '00'; |
|
|
|
|
|
setFormEndHour(`${h}:${m}`); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const updateEndMinute = (m) => { |
|
|
|
|
|
const parts = (formEndHour || '23:00').split(':'); |
|
|
|
|
|
const h = parts.length > 0 ? parts[0] : '23'; |
|
|
|
|
|
setFormEndHour(`${h}:${m}`); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
// Toast alert |
|
|
// Toast alert |
|
|
const [toast, setToast] = useState(null); |
|
|
const [toast, setToast] = useState(null); |
|
|
|
|
|
|
|
|
@ -710,24 +741,52 @@ function App() { |
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> |
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> |
|
|
<div className="flex flex-col gap-1.5"> |
|
|
<div className="flex flex-col gap-1.5"> |
|
|
<label className="text-xs text-gray-400 font-medium">ساعت شروع پنجره مجاز</label> |
|
|
<label className="text-xs text-gray-400 font-medium">ساعت شروع پنجره مجاز</label> |
|
|
<input |
|
|
|
|
|
type="time" |
|
|
|
|
|
value={formStartHour} |
|
|
|
|
|
onChange={(e) => setFormStartHour(e.target.value)} |
|
|
|
|
|
className="bg-black/20 border border-white/5 rounded-lg px-4 py-2 text-white text-sm outline-none focus:border-purple-500" |
|
|
|
|
|
required |
|
|
|
|
|
/> |
|
|
|
|
|
|
|
|
<div className="flex flex-row-reverse items-center gap-2"> |
|
|
|
|
|
<select |
|
|
|
|
|
value={startH || '08'} |
|
|
|
|
|
onChange={(e) => updateStartHour(e.target.value)} |
|
|
|
|
|
className="flex-1 bg-[#1a1625] border border-white/5 rounded-lg px-3 py-2 text-white text-sm outline-none focus:border-purple-500 cursor-pointer" |
|
|
|
|
|
> |
|
|
|
|
|
{HOURS_LIST.map(h => ( |
|
|
|
|
|
<option key={h} value={h} className="bg-slate-900 text-white">{h}</option> |
|
|
|
|
|
))} |
|
|
|
|
|
</select> |
|
|
|
|
|
<span className="text-gray-500 font-bold">:</span> |
|
|
|
|
|
<select |
|
|
|
|
|
value={startM || '00'} |
|
|
|
|
|
onChange={(e) => updateStartMinute(e.target.value)} |
|
|
|
|
|
className="flex-1 bg-[#1a1625] border border-white/5 rounded-lg px-3 py-2 text-white text-sm outline-none focus:border-purple-500 cursor-pointer" |
|
|
|
|
|
> |
|
|
|
|
|
{MINUTES_LIST.map(m => ( |
|
|
|
|
|
<option key={m} value={m} className="bg-slate-900 text-white">{m}</option> |
|
|
|
|
|
))} |
|
|
|
|
|
</select> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div className="flex flex-col gap-1.5"> |
|
|
<div className="flex flex-col gap-1.5"> |
|
|
<label className="text-xs text-gray-400 font-medium">ساعت پایان پنجره مجاز</label> |
|
|
<label className="text-xs text-gray-400 font-medium">ساعت پایان پنجره مجاز</label> |
|
|
<input |
|
|
|
|
|
type="time" |
|
|
|
|
|
value={formEndHour} |
|
|
|
|
|
onChange={(e) => setFormEndHour(e.target.value)} |
|
|
|
|
|
className="bg-black/20 border border-white/5 rounded-lg px-4 py-2 text-white text-sm outline-none focus:border-purple-500" |
|
|
|
|
|
required |
|
|
|
|
|
/> |
|
|
|
|
|
|
|
|
<div className="flex flex-row-reverse items-center gap-2"> |
|
|
|
|
|
<select |
|
|
|
|
|
value={endH || '23'} |
|
|
|
|
|
onChange={(e) => updateEndHour(e.target.value)} |
|
|
|
|
|
className="flex-1 bg-[#1a1625] border border-white/5 rounded-lg px-3 py-2 text-white text-sm outline-none focus:border-purple-500 cursor-pointer" |
|
|
|
|
|
> |
|
|
|
|
|
{HOURS_LIST.map(h => ( |
|
|
|
|
|
<option key={h} value={h} className="bg-slate-900 text-white">{h}</option> |
|
|
|
|
|
))} |
|
|
|
|
|
</select> |
|
|
|
|
|
<span className="text-gray-500 font-bold">:</span> |
|
|
|
|
|
<select |
|
|
|
|
|
value={endM || '00'} |
|
|
|
|
|
onChange={(e) => updateEndMinute(e.target.value)} |
|
|
|
|
|
className="flex-1 bg-[#1a1625] border border-white/5 rounded-lg px-3 py-2 text-white text-sm outline-none focus:border-purple-500 cursor-pointer" |
|
|
|
|
|
> |
|
|
|
|
|
{MINUTES_LIST.map(m => ( |
|
|
|
|
|
<option key={m} value={m} className="bg-slate-900 text-white">{m}</option> |
|
|
|
|
|
))} |
|
|
|
|
|
</select> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
|